polish
This commit is contained in:
parent
e99cda3739
commit
3fb3549997
|
|
@ -30,7 +30,7 @@ final class DefaultMappingTargetFactory implements MappingTargetFactory {
|
||||||
return ClassUtils.hasConstructor(targetType.getType(), null);
|
return ClassUtils.hasConstructor(targetType.getType(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object createTarget(TypeDescriptor targetType) {
|
public Object createTarget(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||||
return BeanUtils.instantiate(targetType.getType());
|
return BeanUtils.instantiate(targetType.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import org.springframework.core.NamedThreadLocal;
|
||||||
* @author Keith Donald
|
* @author Keith Donald
|
||||||
* @see SpelMapper#map(Object, Object)
|
* @see SpelMapper#map(Object, Object)
|
||||||
*/
|
*/
|
||||||
abstract class MappingContextHolder {
|
public abstract class MappingContextHolder {
|
||||||
|
|
||||||
private static final ThreadLocal<Stack<Object>> mappingContextHolder = new NamedThreadLocal<Stack<Object>>(
|
private static final ThreadLocal<Stack<Object>> mappingContextHolder = new NamedThreadLocal<Stack<Object>>(
|
||||||
"Mapping context");
|
"Mapping context");
|
||||||
|
|
|
||||||
|
|
@ -33,10 +33,20 @@ public final class MappingConverter implements GenericConverter {
|
||||||
|
|
||||||
private MappingTargetFactory mappingTargetFactory;
|
private MappingTargetFactory mappingTargetFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Converter that delegates to the mapper to complete the type conversion process.
|
||||||
|
* Uses a {@link DefaultMappingTargetFactory} to create the target object to map and return.
|
||||||
|
* @param mapper the mapper
|
||||||
|
*/
|
||||||
public MappingConverter(Mapper mapper) {
|
public MappingConverter(Mapper mapper) {
|
||||||
this(mapper, new DefaultMappingTargetFactory());
|
this(mapper, new DefaultMappingTargetFactory());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Converter that delegates to the mapper to complete the type conversion process.
|
||||||
|
* Uses the specified MappingTargetFactory to create the target object to map and return.
|
||||||
|
* @param mapper the mapper
|
||||||
|
*/
|
||||||
public MappingConverter(Mapper mapper, MappingTargetFactory mappingTargetFactory) {
|
public MappingConverter(Mapper mapper, MappingTargetFactory mappingTargetFactory) {
|
||||||
this.mapper = mapper;
|
this.mapper = mapper;
|
||||||
this.mappingTargetFactory = mappingTargetFactory;
|
this.mappingTargetFactory = mappingTargetFactory;
|
||||||
|
|
@ -52,7 +62,7 @@ public final class MappingConverter implements GenericConverter {
|
||||||
if (sourceType.isAssignableTo(targetType) && isCopyByReference(sourceType, targetType)) {
|
if (sourceType.isAssignableTo(targetType) && isCopyByReference(sourceType, targetType)) {
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
return createAndMap(targetType, source, sourceType);
|
return createTargetAndMap(source, sourceType, targetType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isCopyByReference(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
private boolean isCopyByReference(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||||
|
|
@ -63,13 +73,13 @@ public final class MappingConverter implements GenericConverter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object createAndMap(TypeDescriptor targetType, Object source, TypeDescriptor sourceType) {
|
private Object createTargetAndMap(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||||
if (this.mappingTargetFactory.supports(targetType)) {
|
if (this.mappingTargetFactory.supports(targetType)) {
|
||||||
Object target = this.mappingTargetFactory.createTarget(targetType);
|
Object target = this.mappingTargetFactory.createTarget(source, sourceType, targetType);
|
||||||
return this.mapper.map(source, target);
|
return this.mapper.map(source, target);
|
||||||
} else {
|
} else {
|
||||||
IllegalStateException cause = new IllegalStateException("["
|
IllegalStateException cause = new IllegalStateException("["
|
||||||
+ this.mappingTargetFactory.getClass().getName() + "] does not support target type ["
|
+ this.mappingTargetFactory.getClass().getName() + "] does not support targetType ["
|
||||||
+ targetType.getName() + "]");
|
+ targetType.getName() + "]");
|
||||||
throw new ConversionFailedException(sourceType, targetType, source, cause);
|
throw new ConversionFailedException(sourceType, targetType, source, cause);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,6 @@ public interface MappingTargetFactory {
|
||||||
* @param targetType the target object type descriptor
|
* @param targetType the target object type descriptor
|
||||||
* @return the target
|
* @return the target
|
||||||
*/
|
*/
|
||||||
public Object createTarget(TypeDescriptor targetType);
|
public Object createTarget(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -170,7 +170,8 @@ public class SpelMapper implements Mapper<Object, Object> {
|
||||||
*/
|
*/
|
||||||
public void addNestedMapper(Class<?> sourceType, Class<?> targetType, Mapper<?, ?> nestedMapper,
|
public void addNestedMapper(Class<?> sourceType, Class<?> targetType, Mapper<?, ?> nestedMapper,
|
||||||
MappingTargetFactory targetFactory) {
|
MappingTargetFactory targetFactory) {
|
||||||
this.conversionService.addGenericConverter(sourceType, targetType, new MappingConverter(nestedMapper));
|
this.conversionService.addGenericConverter(sourceType, targetType, new MappingConverter(nestedMapper,
|
||||||
|
targetFactory));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import java.util.Set;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.core.convert.ConversionService;
|
import org.springframework.core.convert.ConversionService;
|
||||||
|
import org.springframework.core.convert.TypeDescriptor;
|
||||||
import org.springframework.core.convert.converter.Converter;
|
import org.springframework.core.convert.converter.Converter;
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
import org.springframework.expression.AccessException;
|
import org.springframework.expression.AccessException;
|
||||||
|
|
@ -201,6 +202,41 @@ public class SpelMapperTests {
|
||||||
assertEquals("bar and baz", target.nested.foo);
|
assertEquals("bar and baz", target.nested.foo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mapBeanNestedCustomNestedMapperCustomMappingTargetFactory() {
|
||||||
|
PersonDto source = new PersonDto();
|
||||||
|
final NestedDto nested = new NestedDto();
|
||||||
|
nested.foo = "bar";
|
||||||
|
source.setNested(nested);
|
||||||
|
|
||||||
|
Person target = new Person();
|
||||||
|
|
||||||
|
SpelMapper nestedMapper = new SpelMapper();
|
||||||
|
nestedMapper.setAutoMappingEnabled(false);
|
||||||
|
nestedMapper.addMapping("foo").setConverter(new Converter<String, String>() {
|
||||||
|
public String convert(String source) {
|
||||||
|
return source + " and baz";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mapper.addNestedMapper(NestedDto.class, Nested.class, nestedMapper, new MappingTargetFactory() {
|
||||||
|
public boolean supports(TypeDescriptor targetType) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object createTarget(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||||
|
NestedDto nestedDto = (NestedDto) source;
|
||||||
|
assertEquals(nested, nestedDto);
|
||||||
|
return new Nested();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mapper.setAutoMappingEnabled(false);
|
||||||
|
mapper.addMapping("nested");
|
||||||
|
mapper.map(source, target);
|
||||||
|
|
||||||
|
assertEquals("bar and baz", target.nested.foo);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void mapBeanNestedCustomNestedMapperHandCoded() {
|
public void mapBeanNestedCustomNestedMapperHandCoded() {
|
||||||
PersonDto source = new PersonDto();
|
PersonDto source = new PersonDto();
|
||||||
|
|
@ -225,6 +261,37 @@ public class SpelMapperTests {
|
||||||
|
|
||||||
assertEquals("bar and baz", target.nested.foo);
|
assertEquals("bar and baz", target.nested.foo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mapBeanNestedCustomConverterDelegatingToMapper() {
|
||||||
|
PersonDto source = new PersonDto();
|
||||||
|
NestedDto nested = new NestedDto();
|
||||||
|
nested.foo = "bar";
|
||||||
|
source.setNested(nested);
|
||||||
|
|
||||||
|
Person target = new Person();
|
||||||
|
|
||||||
|
mapper.getConverterRegistry().addConverter(new Converter<NestedDto, Nested>() {
|
||||||
|
public Nested convert(NestedDto source) {
|
||||||
|
// allows construction of target to be controlled by the converter
|
||||||
|
Nested nested = new Nested();
|
||||||
|
// mapping can do whatever, here we delegate to nested SpelMapper
|
||||||
|
SpelMapper nestedMapper = new SpelMapper();
|
||||||
|
nestedMapper.addMapping("foo").setConverter(new Converter<String, String>() {
|
||||||
|
public String convert(String source) {
|
||||||
|
return source + " and baz";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return (Nested) nestedMapper.map(source, nested);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mapper.setAutoMappingEnabled(false);
|
||||||
|
mapper.addMapping("nested");
|
||||||
|
mapper.map(source, target);
|
||||||
|
|
||||||
|
assertEquals("bar and baz", target.nested.foo);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void mapList() {
|
public void mapList() {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue