polish
This commit is contained in:
parent
f55b54ec3b
commit
f63c3d5313
|
|
@ -45,6 +45,10 @@ final class FieldToFieldMapping implements SpelMapping {
|
|||
return this.targetField.getExpressionString();
|
||||
}
|
||||
|
||||
public boolean mapsField(String field) {
|
||||
return getSourceField().equals(field);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void map(SpelMappingContext context) {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -38,6 +38,10 @@ final class FieldToMultiFieldMapping implements SpelMapping {
|
|||
return this.sourceField.getExpressionString();
|
||||
}
|
||||
|
||||
public boolean mapsField(String field) {
|
||||
return getSourceField().equals(field);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void map(SpelMappingContext context) {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -101,10 +101,11 @@ public interface MapperBuilder<S, T> {
|
|||
* 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.
|
||||
* 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
|
||||
* @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.
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package org.springframework.mapping.support;
|
||||
|
||||
import org.springframework.core.style.StylerUtils;
|
||||
import org.springframework.mapping.Mapper;
|
||||
|
||||
/**
|
||||
|
|
@ -23,13 +24,29 @@ import org.springframework.mapping.Mapper;
|
|||
*/
|
||||
final class MultiFieldToFieldMapping implements SpelMapping {
|
||||
|
||||
private String[] fields;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private final Mapper multiFieldMapper;
|
||||
|
||||
public MultiFieldToFieldMapping(Mapper<?, ?> multiFieldMapper) {
|
||||
public MultiFieldToFieldMapping(String[] fields, Mapper<?, ?> multiFieldMapper) {
|
||||
this.fields = fields;
|
||||
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")
|
||||
public void map(SpelMappingContext context) {
|
||||
try {
|
||||
|
|
@ -52,7 +69,7 @@ final class MultiFieldToFieldMapping implements SpelMapping {
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public void addMapping(String field, Mapper mapper) {
|
||||
public void addMapping(String field, Mapper<?, ?> mapper) {
|
||||
this.mappings.add(new FieldToMultiFieldMapping(parseSourceField(field), mapper));
|
||||
}
|
||||
|
||||
public void addMapping(Mapper mapper) {
|
||||
this.mappings.add(new MultiFieldToFieldMapping(mapper));
|
||||
public void addMapping(String[] fields, Mapper<?, ?> mapper) {
|
||||
this.mappings.add(new MultiFieldToFieldMapping(fields, mapper));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -240,8 +240,7 @@ final class SpelMapper implements Mapper<Object, Object> {
|
|||
|
||||
private boolean explicitlyMapped(String field) {
|
||||
for (SpelMapping mapping : this.mappings) {
|
||||
if (mapping instanceof FieldToFieldMapping
|
||||
&& ((FieldToFieldMapping) mapping).getSourceField().startsWith(field)) {
|
||||
if (mapping.mapsField(field)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,8 +64,8 @@ final class SpelMapperBuilder<S, T> implements MapperBuilder<S, T> {
|
|||
return this;
|
||||
}
|
||||
|
||||
public MapperBuilder<S, T> addMapping(Mapper<S, T> mapper) {
|
||||
this.mapper.addMapping(mapper);
|
||||
public MapperBuilder<S, T> addMapping(String[] fields, Mapper<S, T> mapper) {
|
||||
this.mapper.addMapping(fields, mapper);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,11 @@ package org.springframework.mapping.support;
|
|||
*/
|
||||
interface SpelMapping {
|
||||
|
||||
/**
|
||||
* Return true if this maps the source field.
|
||||
*/
|
||||
boolean mapsField(String field);
|
||||
|
||||
/**
|
||||
* Execute this mapping.
|
||||
* @param context the mapping context
|
||||
|
|
|
|||
|
|
@ -291,10 +291,11 @@ public class MappingTests {
|
|||
}
|
||||
})
|
||||
// multiple fields to field
|
||||
.addMapping(new Mapper<CreateAccountDto, Account>() {
|
||||
.addMapping(new String[] { "activationDay", "activationTime " },
|
||||
new Mapper<CreateAccountDto, Account>() {
|
||||
public Account map(CreateAccountDto source, Account target) {
|
||||
DateTime dateTime = ISODateTimeFormat.dateTime().parseDateTime(
|
||||
source.getActivationDate() + "T" + source.getActivationTime());
|
||||
source.getActivationDay() + "T" + source.getActivationTime());
|
||||
target.setActivationDateTime(dateTime);
|
||||
return target;
|
||||
}
|
||||
|
|
@ -302,7 +303,7 @@ public class MappingTests {
|
|||
CreateAccountDto dto = new CreateAccountDto();
|
||||
dto.setAccountNumber("123456789");
|
||||
dto.setName("Keith Donald");
|
||||
dto.setActivationDate("2009-10-12");
|
||||
dto.setActivationDay("2009-10-12");
|
||||
dto.setActivationTime("12:00:00.000Z");
|
||||
dto.setAddress("2009BelAireEstates PalmBay FL 35452");
|
||||
Account account = mapper.map(dto, new Account());
|
||||
|
|
@ -500,7 +501,7 @@ public class MappingTests {
|
|||
|
||||
private String address;
|
||||
|
||||
private String activationDate;
|
||||
private String activationDay;
|
||||
|
||||
private String activationTime;
|
||||
|
||||
|
|
@ -528,12 +529,12 @@ public class MappingTests {
|
|||
this.address = address;
|
||||
}
|
||||
|
||||
public String getActivationDate() {
|
||||
return activationDate;
|
||||
public String getActivationDay() {
|
||||
return activationDay;
|
||||
}
|
||||
|
||||
public void setActivationDate(String activationDate) {
|
||||
this.activationDate = activationDate;
|
||||
public void setActivationDay(String activationDay) {
|
||||
this.activationDay = activationDay;
|
||||
}
|
||||
|
||||
public String getActivationTime() {
|
||||
|
|
|
|||
|
|
@ -1599,7 +1599,8 @@ public void testDefaultSpelMappingBehavior() {
|
|||
<title>Registering Explicit Mappings</title>
|
||||
<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>.
|
||||
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>
|
||||
<programlisting language="java"><![CDATA[
|
||||
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.
|
||||
Handle a situation like this by explicitly registering a mapping rule:
|
||||
</para>
|
||||
<programlisting language="java">builder.addMapping("name", "fullName")</programlisting>
|
||||
<programlisting language="java"><![CDATA[
|
||||
builder.addMapping("name", "fullName")]]>
|
||||
</programlisting>
|
||||
<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.
|
||||
</para>
|
||||
</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">
|
||||
<title>Forcing Explicit Mappings</title>
|
||||
<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>
|
||||
<programlisting language="java"><![CDATA[
|
||||
builder.setAutoMappingEnabled(false);]]>
|
||||
|
|
@ -1651,14 +1696,14 @@ builder.addMapping("name", "fullName").setConverter() { new Converter<String, St
|
|||
<title>Ignoring Fields</title>
|
||||
<para>
|
||||
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>
|
||||
<programlisting language="java">builder.setExcludedFields("name");</programlisting>
|
||||
</section>
|
||||
<section id="mapper.SpelMapper-CustomTypeConverters">
|
||||
<title>Registering Custom Type Converters</title>
|
||||
<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>
|
||||
<programlisting language="java"><![CDATA[
|
||||
builder.addConverter(new Converter<String, Date>() {
|
||||
|
|
@ -1675,7 +1720,7 @@ builder.addConverter(new Converter<String, Date>() {
|
|||
<section id="mapper.SpelMapper-CustomNestedMappers">
|
||||
<title>Registering Custom Nested Mappers</title>
|
||||
<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:
|
||||
</para>
|
||||
<programlisting language="java"><![CDATA[
|
||||
|
|
@ -1687,7 +1732,7 @@ builder.addNestedMapper(new Mapper<AddressDto, Address>() {
|
|||
});]]>
|
||||
</programlisting>
|
||||
<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.
|
||||
</para>
|
||||
</section>
|
||||
|
|
|
|||
Loading…
Reference in New Issue