Search code examples
javaspring-bootjava-8java-streamdozer

How to clone an object and recursively set Id to Null?


Here my use case :

I have 4 classes A,B,C,D

  • class A contains an object ( type B ) and a list of objects ( type C )
  • class B contains an object ( type D )

I want to clone the class A , and set the id to null recursively.

Here an example :

public class ClassA {

    private Long id;
    private String name;
    private boolean ok;
    private ClassB classB;
    private List<ClassC> classCList;

}

public class ClassB {

    private Long id;
    private String name;
    private ClassD classD;

}

public class ClassC{

    private Long id;
    private String name;

}

public class ClassD{

    private Long id;
    private String name;

}

I developed two functions to implement that :
First method :

public ClassA prepareClassA(ClassA detail) {

   Optional.ofNullable(detail).ifPresent( detail -> {
    detail.setId(null);
    Optional.ofNullable(detail).map(ClassA::getClassB)
            .ifPresent(objectB -> objectB.setId(null));

   Optional.ofNullable(detail).map(ClassA::getClassB).map(ClassB::getClassD)
            .ifPresent(objectB -> objectB.setId(null));

   Optional.ofNullable(detail).map(ClassA::getClassCList).
        .ifPresent(items -> items.stream().forEach(item -> {
            item.setId(null);
        }));

   }
}

Second method : ( included dozerMapper )

<dependency>
    <groupId>commons-beanutils</groupId>
    <artifactId>commons-beanutils</artifactId>
    <version>1.9.3</version>
</dependency>

<dependency>
    <groupId>net.sf.dozer</groupId>
    <artifactId>dozer</artifactId>
    <version>5.5.1</version>
</dependency>

And i used the DozerBeanMapper implementation

public ClassA prepareClassA(ClassA detail) {

    ClassA objectA = new ClassA();

    DozerBeanMapper dozerBeanMapper = new DozerBeanMapper();

    BeanMappingBuilder bean = beanMappingBuilder(ClassA.class);

    dozerBeanMapper.addMapping(bean);
    Optional.ofNullable(detail).ifPresent(detail -> dozerBeanMapper.map(detail, objectA));
    return details;
}


public BeanMappingBuilder beanMappingBuilder(Class<?> source) {
    return new BeanMappingBuilder() {
        @Override
        protected void configure() {
            mapping(source, source,
                TypeMappingOptions .wildcard(true)
                //Here i have to do my work ?
                //TypeMappingOptions.mapNull(true)
            );
        }
    };
}

I want to have this result :

ClassA testA = new ClassA();
//fill all the objects in objectA with id != null

ClassA testA_convert = prepareClassA(testA);

// testA_convert.getId() must be null
// testA_convert.getClassB().getId() must be null
// testA_convert.getClassB().getClassD().getId() must be null
// testA_convert.getClassCList().forEach( element -> element.getId()  must be null

Questions :

  • Is there any existing libary that can solve my problèm ?
  • Can DozerMapper do that ?
  • What is the best way to do that ?

Best regards


Solution

  • I think that i found an easy way to do it :

    implement Gson library :

    <dependency>
       <groupId>com.google.code.gson</groupId>
       <artifactId>gson</artifactId>
      <version>2.2.4</version>
    </dependency>
    

    And add

    public class ClassA {
    
       private Long id;
    
       @Expose
       private String name;
    
       @Expose
       private boolean ok;
    
       @Expose
       private ClassB classB;
    
       @Expose
       private List<ClassC> classCList;
    
    }
    
    public class ClassB {
    
       private Long id;
    
       @Expose
       private String name;
    
       @Expose
       private ClassD classD;
    
    }
    

    I put @Expose onto all fields != id

    Here the implementation in my main class

        import com.google.gson.annotations.Expose;
    
        public ClassA prepareClassA(ClassA detail) {
    
           Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
           ClassA object_A = gson.fromJson(gson.toJson(detail),ClassA.class);
           return  object_A;
    
        }
    

    And it works .

    But , is there a way to put @Expose only one time onto the class definition for all attributes ( excluding Id )

    Example :

    @Expose( exclude ="id" )
    public class ClassB {
    
       private Long id;
       private String name;
       private ClassD classD;
    
    }
    

    Any Help ?