如何克隆一个对象并递归地将 Id 设置为 Null?
How to clone an object and recursively set Id to Null?
这是我的用例:
我有 4 classes A,B,C,D
- class A 包含一个对象(类型 B)和一个对象列表(类型 C)
- class B 包含一个对象(类型 D)
我想克隆 class A ,并递归地将 id 设置为 null。
这里有一个例子:
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;
}
我开发了两个函数来实现:
第一种方法:
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);
}));
}
}
第二种方法:(包括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>
我使用了 DozerBeanMapper 实现
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)
);
}
};
}
我想要这样的结果:
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
问题:
- 是否有任何现有的库可以解决我的问题?
- DozerMapper 能做到吗?
- 最好的方法是什么?
此致
Is there any existing library that can solve my problem ?
是的,MapStruct 可以选择忽略您想要的属性。
比如定义一个配置接口
@Mapper(componentModel = "spring")
public interface DomainDtoMapper {
@Mapping(source = "id", target = "id", ignore = true)
ClassA map(ClassA cla);
@Mapping(source = "id", target = "id", ignore = true)
ClassB map(ClassB clb);
//...
}
然后只需自动装配 DomainDtoMapper
并调用该方法,它将检查所有映射规则并相应地复制:
@Autowire DomainDtoMapper mapper;
//...
public ClassA prepareClassA(ClassA detail) {
return mapper.map(detail);
}
我想我找到了一个简单的方法:
实施 Gson 库:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.2.4</version>
</dependency>
并添加
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;
}
我把@Expose 放在所有字段上!= id
这里是我主要的实现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;
}
并且有效。
但是 ,有没有办法将@Expose 仅一次放入所有属性(不包括 Id )
的 class 定义中
示例:
@Expose( exclude ="id" )
public class ClassB {
private Long id;
private String name;
private ClassD classD;
}
有什么帮助吗?
如果您已经克隆了您的对象并希望在没有 NPE 的情况下将 id 设置为 null,那么您可以为此创建一个帮助程序接口:
interface Nullify<T> {
void apply(T obj);
default <G> Nullify<T> andThen(Function<T, G> function, Nullify<G> nullify) {
return (T t) -> {
apply(t);
G g = function.apply(t);
if(g != null) {
nullify.apply(g);
}
};
}
}
和用法
Nullify<ClassB> bNull = b -> b.setId(null);
bNull = bNull.andThen(ClassB::getClassD, d -> d.setId(null));
Nullify<ClassA> aNull = a -> a.setId(null);
aNull.andThen(ClassA::getClassB, bNull)
.andThen(ClassA::getClassCList, classCList -> classCList.forEach(c -> c.setId(null)))
.apply(classAObject);
虽然最好配置 clone/copy 方法来忽略 id(例如像 MapStruct)
这是我的用例:
我有 4 classes A,B,C,D
- class A 包含一个对象(类型 B)和一个对象列表(类型 C)
- class B 包含一个对象(类型 D)
我想克隆 class A ,并递归地将 id 设置为 null。
这里有一个例子:
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;
}
我开发了两个函数来实现:
第一种方法:
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);
}));
}
}
第二种方法:(包括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>
我使用了 DozerBeanMapper 实现
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)
);
}
};
}
我想要这样的结果:
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
问题:
- 是否有任何现有的库可以解决我的问题?
- DozerMapper 能做到吗?
- 最好的方法是什么?
此致
Is there any existing library that can solve my problem ?
是的,MapStruct 可以选择忽略您想要的属性。
比如定义一个配置接口
@Mapper(componentModel = "spring")
public interface DomainDtoMapper {
@Mapping(source = "id", target = "id", ignore = true)
ClassA map(ClassA cla);
@Mapping(source = "id", target = "id", ignore = true)
ClassB map(ClassB clb);
//...
}
然后只需自动装配 DomainDtoMapper
并调用该方法,它将检查所有映射规则并相应地复制:
@Autowire DomainDtoMapper mapper;
//...
public ClassA prepareClassA(ClassA detail) {
return mapper.map(detail);
}
我想我找到了一个简单的方法:
实施 Gson 库:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.2.4</version>
</dependency>
并添加
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;
}
我把@Expose 放在所有字段上!= id
这里是我主要的实现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;
}
并且有效。
但是 ,有没有办法将@Expose 仅一次放入所有属性(不包括 Id )
的 class 定义中示例:
@Expose( exclude ="id" )
public class ClassB {
private Long id;
private String name;
private ClassD classD;
}
有什么帮助吗?
如果您已经克隆了您的对象并希望在没有 NPE 的情况下将 id 设置为 null,那么您可以为此创建一个帮助程序接口:
interface Nullify<T> {
void apply(T obj);
default <G> Nullify<T> andThen(Function<T, G> function, Nullify<G> nullify) {
return (T t) -> {
apply(t);
G g = function.apply(t);
if(g != null) {
nullify.apply(g);
}
};
}
}
和用法
Nullify<ClassB> bNull = b -> b.setId(null);
bNull = bNull.andThen(ClassB::getClassD, d -> d.setId(null));
Nullify<ClassA> aNull = a -> a.setId(null);
aNull.andThen(ClassA::getClassB, bNull)
.andThen(ClassA::getClassCList, classCList -> classCList.forEach(c -> c.setId(null)))
.apply(classAObject);
虽然最好配置 clone/copy 方法来忽略 id(例如像 MapStruct)