polish
This commit is contained in:
parent
f55b54ec3b
commit
f63c3d5313
|
|
@ -45,6 +45,10 @@ final class FieldToFieldMapping implements SpelMapping {
|
||||||
return this.targetField.getExpressionString();
|
return this.targetField.getExpressionString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean mapsField(String field) {
|
||||||
|
return getSourceField().equals(field);
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void map(SpelMappingContext context) {
|
public void map(SpelMappingContext context) {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,10 @@ final class FieldToMultiFieldMapping implements SpelMapping {
|
||||||
return this.sourceField.getExpressionString();
|
return this.sourceField.getExpressionString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean mapsField(String field) {
|
||||||
|
return getSourceField().equals(field);
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void map(SpelMappingContext context) {
|
public void map(SpelMappingContext context) {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -101,10 +101,11 @@ public interface MapperBuilder<S, T> {
|
||||||
* Register a mapping between multiple source fields and a single target field.
|
* Register a mapping between multiple source fields and a single target field.
|
||||||
* For example, calling <code>addMapping(dateAndTimeFieldsToDateTimeFieldMapper)</code> might register a mapping that maps the <code>date</code> and <code>time</code> fields on the source to the <code>dateTime</code> field on the target.
|
* For example, calling <code>addMapping(dateAndTimeFieldsToDateTimeFieldMapper)</code> might register a mapping that maps the <code>date</code> and <code>time</code> fields on the source to the <code>dateTime</code> field on the target.
|
||||||
* The provided {@link Mapper} will be passed the source object S for its source and the target object T for its target.
|
* The provided {@link Mapper} will be passed the source object S for its source and the target object T for its target.
|
||||||
|
* @param fields the source field mapping expressions
|
||||||
* @param mapper the fields to field mapper
|
* @param mapper the fields to field mapper
|
||||||
* @return this, for configuring additional field mapping options fluently
|
* @return this, for configuring additional field mapping options fluently
|
||||||
*/
|
*/
|
||||||
MapperBuilder<S, T> addMapping(Mapper<S, T> mapper);
|
MapperBuilder<S, T> addMapping(String[] fields, Mapper<S, T> mapper);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a Mapper that will be used to map between nested source and target fields of a specific sourceType/targetType pair.
|
* Register a Mapper that will be used to map between nested source and target fields of a specific sourceType/targetType pair.
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package org.springframework.mapping.support;
|
package org.springframework.mapping.support;
|
||||||
|
|
||||||
|
import org.springframework.core.style.StylerUtils;
|
||||||
import org.springframework.mapping.Mapper;
|
import org.springframework.mapping.Mapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -23,13 +24,29 @@ import org.springframework.mapping.Mapper;
|
||||||
*/
|
*/
|
||||||
final class MultiFieldToFieldMapping implements SpelMapping {
|
final class MultiFieldToFieldMapping implements SpelMapping {
|
||||||
|
|
||||||
|
private String[] fields;
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private final Mapper multiFieldMapper;
|
private final Mapper multiFieldMapper;
|
||||||
|
|
||||||
public MultiFieldToFieldMapping(Mapper<?, ?> multiFieldMapper) {
|
public MultiFieldToFieldMapping(String[] fields, Mapper<?, ?> multiFieldMapper) {
|
||||||
|
this.fields = fields;
|
||||||
this.multiFieldMapper = multiFieldMapper;
|
this.multiFieldMapper = multiFieldMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String[] getSourceFields() {
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean mapsField(String field) {
|
||||||
|
for (String f : this.fields) {
|
||||||
|
if (f.equals(field)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void map(SpelMappingContext context) {
|
public void map(SpelMappingContext context) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -52,7 +69,7 @@ final class MultiFieldToFieldMapping implements SpelMapping {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "[MultiFieldToFieldMapping<" + this.multiFieldMapper + ">]";
|
return "[MultiFieldToFieldMapping<" + StylerUtils.style(this.fields) + " -> " + this.multiFieldMapper + ">]";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -78,12 +78,12 @@ final class SpelMapper implements Mapper<Object, Object> {
|
||||||
this.mappings.add(mapping);
|
this.mappings.add(mapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addMapping(String field, Mapper mapper) {
|
public void addMapping(String field, Mapper<?, ?> mapper) {
|
||||||
this.mappings.add(new FieldToMultiFieldMapping(parseSourceField(field), mapper));
|
this.mappings.add(new FieldToMultiFieldMapping(parseSourceField(field), mapper));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addMapping(Mapper mapper) {
|
public void addMapping(String[] fields, Mapper<?, ?> mapper) {
|
||||||
this.mappings.add(new MultiFieldToFieldMapping(mapper));
|
this.mappings.add(new MultiFieldToFieldMapping(fields, mapper));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -240,8 +240,7 @@ final class SpelMapper implements Mapper<Object, Object> {
|
||||||
|
|
||||||
private boolean explicitlyMapped(String field) {
|
private boolean explicitlyMapped(String field) {
|
||||||
for (SpelMapping mapping : this.mappings) {
|
for (SpelMapping mapping : this.mappings) {
|
||||||
if (mapping instanceof FieldToFieldMapping
|
if (mapping.mapsField(field)) {
|
||||||
&& ((FieldToFieldMapping) mapping).getSourceField().startsWith(field)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,8 +64,8 @@ final class SpelMapperBuilder<S, T> implements MapperBuilder<S, T> {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MapperBuilder<S, T> addMapping(Mapper<S, T> mapper) {
|
public MapperBuilder<S, T> addMapping(String[] fields, Mapper<S, T> mapper) {
|
||||||
this.mapper.addMapping(mapper);
|
this.mapper.addMapping(fields, mapper);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,11 @@ package org.springframework.mapping.support;
|
||||||
*/
|
*/
|
||||||
interface SpelMapping {
|
interface SpelMapping {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if this maps the source field.
|
||||||
|
*/
|
||||||
|
boolean mapsField(String field);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute this mapping.
|
* Execute this mapping.
|
||||||
* @param context the mapping context
|
* @param context the mapping context
|
||||||
|
|
|
||||||
|
|
@ -291,18 +291,19 @@ public class MappingTests {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// multiple fields to field
|
// multiple fields to field
|
||||||
.addMapping(new Mapper<CreateAccountDto, Account>() {
|
.addMapping(new String[] { "activationDay", "activationTime " },
|
||||||
public Account map(CreateAccountDto source, Account target) {
|
new Mapper<CreateAccountDto, Account>() {
|
||||||
DateTime dateTime = ISODateTimeFormat.dateTime().parseDateTime(
|
public Account map(CreateAccountDto source, Account target) {
|
||||||
source.getActivationDate() + "T" + source.getActivationTime());
|
DateTime dateTime = ISODateTimeFormat.dateTime().parseDateTime(
|
||||||
target.setActivationDateTime(dateTime);
|
source.getActivationDay() + "T" + source.getActivationTime());
|
||||||
return target;
|
target.setActivationDateTime(dateTime);
|
||||||
}
|
return target;
|
||||||
}).getMapper();
|
}
|
||||||
|
}).getMapper();
|
||||||
CreateAccountDto dto = new CreateAccountDto();
|
CreateAccountDto dto = new CreateAccountDto();
|
||||||
dto.setAccountNumber("123456789");
|
dto.setAccountNumber("123456789");
|
||||||
dto.setName("Keith Donald");
|
dto.setName("Keith Donald");
|
||||||
dto.setActivationDate("2009-10-12");
|
dto.setActivationDay("2009-10-12");
|
||||||
dto.setActivationTime("12:00:00.000Z");
|
dto.setActivationTime("12:00:00.000Z");
|
||||||
dto.setAddress("2009BelAireEstates PalmBay FL 35452");
|
dto.setAddress("2009BelAireEstates PalmBay FL 35452");
|
||||||
Account account = mapper.map(dto, new Account());
|
Account account = mapper.map(dto, new Account());
|
||||||
|
|
@ -500,7 +501,7 @@ public class MappingTests {
|
||||||
|
|
||||||
private String address;
|
private String address;
|
||||||
|
|
||||||
private String activationDate;
|
private String activationDay;
|
||||||
|
|
||||||
private String activationTime;
|
private String activationTime;
|
||||||
|
|
||||||
|
|
@ -528,12 +529,12 @@ public class MappingTests {
|
||||||
this.address = address;
|
this.address = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getActivationDate() {
|
public String getActivationDay() {
|
||||||
return activationDate;
|
return activationDay;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setActivationDate(String activationDate) {
|
public void setActivationDay(String activationDay) {
|
||||||
this.activationDate = activationDate;
|
this.activationDay = activationDay;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getActivationTime() {
|
public String getActivationTime() {
|
||||||
|
|
|
||||||
|
|
@ -1599,7 +1599,8 @@ public void testDefaultSpelMappingBehavior() {
|
||||||
<title>Registering Explicit Mappings</title>
|
<title>Registering Explicit Mappings</title>
|
||||||
<para>
|
<para>
|
||||||
When default mapping rules are not sufficient, explicit mapping rules can be registered by obtaining a <classname>MapperBuilder</classname> and using it to construct a <classname>Mapper</classname>.
|
When default mapping rules are not sufficient, explicit mapping rules can be registered by obtaining a <classname>MapperBuilder</classname> and using it to construct a <classname>Mapper</classname>.
|
||||||
Explicit mapping rules always override the default:
|
Explicit mapping rules always override the default.
|
||||||
|
The MapperBuilder provides a fluent API for registering object-to-object Mapping rules:
|
||||||
</para>
|
</para>
|
||||||
<programlisting language="java"><![CDATA[
|
<programlisting language="java"><![CDATA[
|
||||||
Mapper<PersonDto, Person> mapper =
|
Mapper<PersonDto, Person> mapper =
|
||||||
|
|
@ -1616,16 +1617,60 @@ Mapper<PersonDto, Person> mapper =
|
||||||
Since the two property names are not the same, default auto-mapping would never be performed.
|
Since the two property names are not the same, default auto-mapping would never be performed.
|
||||||
Handle a situation like this by explicitly registering a mapping rule:
|
Handle a situation like this by explicitly registering a mapping rule:
|
||||||
</para>
|
</para>
|
||||||
<programlisting language="java">builder.addMapping("name", "fullName")</programlisting>
|
<programlisting language="java"><![CDATA[
|
||||||
|
builder.addMapping("name", "fullName")]]>
|
||||||
|
</programlisting>
|
||||||
<para>
|
<para>
|
||||||
In this example, the <literal>name</literal> field will be mapped to the <literal>fullName</literal> field when the mapper is executed.
|
In the example above, the <literal>name</literal> field will be mapped to the <literal>fullName</literal> field when the mapper is executed.
|
||||||
No default mapping will be performed for <literal>name</literal> since an explicit mapping rule has been configured for this field.
|
No default mapping will be performed for <literal>name</literal> since an explicit mapping rule has been configured for this field.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
<section id="mapping.SpelMapper-Explicit-singleFieldToMultipleField">
|
||||||
|
<title>Mapping a single field value to multiple fields</title>
|
||||||
|
<para>
|
||||||
|
Suppose you need to map <literal>PersonDto.name</literal> to <literal>Person.firstName</literal> and <literal>Person.lastName</literal>.
|
||||||
|
Handle a field-to-multi-field requirement like this by explicitly registering a mapping rule:
|
||||||
|
</para>
|
||||||
|
<programlisting language="java"><![CDATA[
|
||||||
|
builder.addMapping("name", new Mapper<String, Person>() {
|
||||||
|
public Person map(String name, Person person) {
|
||||||
|
String[] names = name.split(" ");
|
||||||
|
person.setFirstName(names[0]);
|
||||||
|
person.setLastName(names[1]);
|
||||||
|
return person;
|
||||||
|
}
|
||||||
|
});]]>
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
In the example above, the first part of the <literal>name</literal> field will be mapped to the <literal>firstName</literal> field and the second part will be mapped to the <literal>lastName</literal> field.
|
||||||
|
No default mapping will be performed for <literal>name</literal> since an explicit mapping rule has been configured for this field.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
<section id="mapping.SpelMapper-Explicit-multipleFieldsToField">
|
||||||
|
<title>Mapping a single field value to multiple fields</title>
|
||||||
|
<para>
|
||||||
|
Suppose you need to map <literal>CreateAccountDto.activationDay</literal> and <literal>CreateAccountDto.activationTime</literal> to <literal>Account.activationDateTime</literal>.
|
||||||
|
Handle a multi-field-to-field requirement like this by explicitly registering a mapping rule:
|
||||||
|
</para>
|
||||||
|
<programlisting language="java"><![CDATA[
|
||||||
|
builder.addMapping(new String[] { "activationDay", "activationTime" }, new Mapper<CreateAccountDto, AccountDto>() {
|
||||||
|
public Account map(CreateAccountDto dto, Account account) {
|
||||||
|
DateTime dateTime = ISODateTimeFormat.dateTime().parseDateTime(
|
||||||
|
dto.getActivationDay() + "T" + dto.getActivationTime());
|
||||||
|
account.setActivationDateTime(dateTime);
|
||||||
|
return account;
|
||||||
|
}
|
||||||
|
});]]>
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
In the example above, the <literal>activationDay</literal> and <literal>activationTime</literal> fields are mapped to the single <literal>activationDateTime</literal> field.
|
||||||
|
No default mapping is performed for <literal>activationDay</literal> and <literal>activationTime</literal> since an explicit mapping rule has been configured for these fields.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
<section id="mapping.SpelMapper-Explicit-forcing">
|
<section id="mapping.SpelMapper-Explicit-forcing">
|
||||||
<title>Forcing Explicit Mappings</title>
|
<title>Forcing Explicit Mappings</title>
|
||||||
<para>
|
<para>
|
||||||
You can require that all mapping rules must be defined explicitly by disabling the "auto mapping" feature:
|
You can require that all mapping rules be defined explicitly by disabling the "auto mapping" feature:
|
||||||
</para>
|
</para>
|
||||||
<programlisting language="java"><![CDATA[
|
<programlisting language="java"><![CDATA[
|
||||||
builder.setAutoMappingEnabled(false);]]>
|
builder.setAutoMappingEnabled(false);]]>
|
||||||
|
|
@ -1651,14 +1696,14 @@ builder.addMapping("name", "fullName").setConverter() { new Converter<String, St
|
||||||
<title>Ignoring Fields</title>
|
<title>Ignoring Fields</title>
|
||||||
<para>
|
<para>
|
||||||
Sometimes you need to exclude a specific field on a source object from being mapped.
|
Sometimes you need to exclude a specific field on a source object from being mapped.
|
||||||
Do this by marking a mapping as excluded:
|
Do this by marking one or more source fields as excluded:
|
||||||
</para>
|
</para>
|
||||||
<programlisting language="java">builder.setExcludedFields("name");</programlisting>
|
<programlisting language="java">builder.setExcludedFields("name");</programlisting>
|
||||||
</section>
|
</section>
|
||||||
<section id="mapper.SpelMapper-CustomTypeConverters">
|
<section id="mapper.SpelMapper-CustomTypeConverters">
|
||||||
<title>Registering Custom Type Converters</title>
|
<title>Registering Custom Type Converters</title>
|
||||||
<para>
|
<para>
|
||||||
You can also install Converters to convert values of different types in a custom way:
|
You may also install Converters to convert values of different types in a custom way:
|
||||||
</para>
|
</para>
|
||||||
<programlisting language="java"><![CDATA[
|
<programlisting language="java"><![CDATA[
|
||||||
builder.addConverter(new Converter<String, Date>() {
|
builder.addConverter(new Converter<String, Date>() {
|
||||||
|
|
@ -1675,7 +1720,7 @@ builder.addConverter(new Converter<String, Date>() {
|
||||||
<section id="mapper.SpelMapper-CustomNestedMappers">
|
<section id="mapper.SpelMapper-CustomNestedMappers">
|
||||||
<title>Registering Custom Nested Mappers</title>
|
<title>Registering Custom Nested Mappers</title>
|
||||||
<para>
|
<para>
|
||||||
When mapping between two large object graphs, you may need to register explicit mapping rules for nested bean properties.
|
When mapping between two object graphs, you may find you need to register explicit mapping rules for nested bean properties.
|
||||||
Do this by adding a nested Mapper:
|
Do this by adding a nested Mapper:
|
||||||
</para>
|
</para>
|
||||||
<programlisting language="java"><![CDATA[
|
<programlisting language="java"><![CDATA[
|
||||||
|
|
@ -1687,7 +1732,7 @@ builder.addNestedMapper(new Mapper<AddressDto, Address>() {
|
||||||
});]]>
|
});]]>
|
||||||
</programlisting>
|
</programlisting>
|
||||||
<para>
|
<para>
|
||||||
The example above registers a nested Mapper that will map nested AddressDto properties to nested Address properties.
|
The example Mapper above will map nested AddressDto properties to nested Address properties.
|
||||||
This particular nested Mapper is "hand-coded", but it could have easily been another Mapper instance built by a MapperBuilder.
|
This particular nested Mapper is "hand-coded", but it could have easily been another Mapper instance built by a MapperBuilder.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue