mapper initial commit
This commit is contained in:
parent
5c055ed6dd
commit
341835a142
|
|
@ -572,7 +572,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (InstantiationException e) {
|
} catch (InstantiationException e) {
|
||||||
throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + name, "Could not instantiate propertyType [" + type.getName() + "] to auto-grow nestd property path");
|
throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + name, "Could not instantiate propertyType [" + type.getName() + "] to auto-grow nested property path");
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + name, "Could not instantiate propertyType [" + type.getName() + "] to auto-grow nested property path");
|
throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + name, "Could not instantiate propertyType [" + type.getName() + "] to auto-grow nested property path");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2009 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps between a source and target.
|
||||||
|
* @author Keith Donald
|
||||||
|
* @param <S> the source type mapped from
|
||||||
|
* @param <T> the target type mapped to
|
||||||
|
*/
|
||||||
|
public interface Mapper<S, T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map the source to the target.
|
||||||
|
* @param source the source to map from
|
||||||
|
* @param target the target to map to
|
||||||
|
* @throws MappingException if the mapping process failed
|
||||||
|
*/
|
||||||
|
void map(S source, T target);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2009 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.mapping;
|
||||||
|
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown in a map operation fails.
|
||||||
|
* @see Mapper#map(Object, Object)
|
||||||
|
* @author Keith Donald
|
||||||
|
*/
|
||||||
|
public class MappingException extends RuntimeException {
|
||||||
|
|
||||||
|
private List<MappingFailure> mappingFailures;
|
||||||
|
|
||||||
|
public MappingException(List<MappingFailure> mappingFailures) {
|
||||||
|
super((String) null);
|
||||||
|
this.mappingFailures = mappingFailures;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMappingFailureCount() {
|
||||||
|
return this.mappingFailures.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<MappingFailure> getMappingFailures() {
|
||||||
|
return this.mappingFailures;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage() {
|
||||||
|
StringBuilder sb = new StringBuilder(getMappingFailureCount() + " mapping failure(s) occurred:");
|
||||||
|
int i = 1;
|
||||||
|
for (Iterator<MappingFailure> it = this.mappingFailures.iterator(); it.hasNext(); i++) {
|
||||||
|
MappingFailure failure = it.next();
|
||||||
|
sb.append(" #").append(i + ") ").append(failure.getMessage());
|
||||||
|
if (it.hasNext()) {
|
||||||
|
sb.append(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void printStackTrace(PrintStream ps) {
|
||||||
|
super.printStackTrace(ps);
|
||||||
|
synchronized (ps) {
|
||||||
|
ps.println("Failure cause traces:");
|
||||||
|
int i = 1;
|
||||||
|
for (Iterator<MappingFailure> it = this.mappingFailures.iterator(); it.hasNext(); i++) {
|
||||||
|
MappingFailure failure = it.next();
|
||||||
|
ps.println("- MappingFailure #" + i + " Cause: ");
|
||||||
|
Throwable t = failure.getCause();
|
||||||
|
if (t != null) {
|
||||||
|
t.printStackTrace(ps);
|
||||||
|
} else {
|
||||||
|
ps.println("null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void printStackTrace(PrintWriter pw) {
|
||||||
|
super.printStackTrace(pw);
|
||||||
|
synchronized (pw) {
|
||||||
|
pw.println("Failure cause traces:");
|
||||||
|
int i = 1;
|
||||||
|
for (Iterator<MappingFailure> it = this.mappingFailures.iterator(); it.hasNext(); i++) {
|
||||||
|
MappingFailure failure = it.next();
|
||||||
|
pw.println("- MappingFailure #" + i + " Cause: ");
|
||||||
|
Throwable t = failure.getCause();
|
||||||
|
if (t != null) {
|
||||||
|
t.printStackTrace(pw);
|
||||||
|
} else {
|
||||||
|
pw.println("null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2009 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates an individual mapping failed.
|
||||||
|
* @author Keith Donald
|
||||||
|
*/
|
||||||
|
public class MappingFailure {
|
||||||
|
|
||||||
|
private final Throwable cause;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new mapping failure caused by the exception.
|
||||||
|
* @param cause the failure cause
|
||||||
|
*/
|
||||||
|
public MappingFailure(Throwable cause) {
|
||||||
|
this.cause = cause;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The failure message.
|
||||||
|
*/
|
||||||
|
public String getMessage() {
|
||||||
|
return getCause().getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cause of this failure.
|
||||||
|
*/
|
||||||
|
public Throwable getCause() {
|
||||||
|
return cause;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "[MappingFailure cause = " + cause + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2009 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.mapping.support;
|
||||||
|
|
||||||
|
import java.beans.PropertyDescriptor;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.core.convert.ConversionService;
|
||||||
|
import org.springframework.expression.EvaluationContext;
|
||||||
|
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||||
|
import org.springframework.expression.spel.support.StandardTypeConverter;
|
||||||
|
|
||||||
|
class BeanMappableType implements MappableType<Object> {
|
||||||
|
|
||||||
|
public Set<String> getFields(Object object) {
|
||||||
|
Set<String> fields = new LinkedHashSet<String>();
|
||||||
|
PropertyDescriptor[] descriptors = BeanUtils.getPropertyDescriptors(object.getClass());
|
||||||
|
for (PropertyDescriptor descriptor : descriptors) {
|
||||||
|
String propertyName = descriptor.getName();
|
||||||
|
if (propertyName.equals("class")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fields.add(descriptor.getName());
|
||||||
|
}
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EvaluationContext getEvaluationContext(Object instance, ConversionService conversionService) {
|
||||||
|
StandardEvaluationContext context = new StandardEvaluationContext(instance);
|
||||||
|
context.setTypeConverter(new StandardTypeConverter(conversionService));
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2009 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.mapping.support;
|
||||||
|
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.springframework.context.expression.MapAccessor;
|
||||||
|
import org.springframework.core.convert.ConversionService;
|
||||||
|
import org.springframework.expression.EvaluationContext;
|
||||||
|
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||||
|
import org.springframework.expression.spel.support.StandardTypeConverter;
|
||||||
|
|
||||||
|
class MapMappableType implements MappableType<Map<? extends Object, ? extends Object>> {
|
||||||
|
|
||||||
|
public Set<String> getFields(Map<? extends Object, ? extends Object> object) {
|
||||||
|
LinkedHashSet<String> fields = new LinkedHashSet<String>(object.size(), 1);
|
||||||
|
for (Object key : object.keySet()) {
|
||||||
|
if (key != null && key instanceof String) {
|
||||||
|
fields.add((String) key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EvaluationContext getEvaluationContext(Map<? extends Object, ? extends Object> object,
|
||||||
|
ConversionService conversionService) {
|
||||||
|
StandardEvaluationContext context = new StandardEvaluationContext(object);
|
||||||
|
context.setTypeConverter(new StandardTypeConverter(conversionService));
|
||||||
|
context.addPropertyAccessor(new MapAccessor());
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2009 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.mapping.support;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.springframework.core.convert.ConversionService;
|
||||||
|
import org.springframework.expression.EvaluationContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulates mapping context for a type of object.
|
||||||
|
* @param <T> the object type
|
||||||
|
* @author Keith Donald
|
||||||
|
*/
|
||||||
|
interface MappableType<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The fields of the object that are eligible for mapping, including any nested fields.
|
||||||
|
*/
|
||||||
|
Set<String> getFields(T object);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A evaluation context for accessing the object.
|
||||||
|
*/
|
||||||
|
EvaluationContext getEvaluationContext(T object, ConversionService conversionService);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2009 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.mapping.support;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.springframework.core.convert.converter.Converter;
|
||||||
|
import org.springframework.core.convert.converter.ConverterFactory;
|
||||||
|
import org.springframework.core.convert.support.ConverterFactoryGenericConverter;
|
||||||
|
import org.springframework.core.convert.support.ConverterGenericConverter;
|
||||||
|
import org.springframework.core.convert.support.GenericConverter;
|
||||||
|
import org.springframework.expression.EvaluationContext;
|
||||||
|
import org.springframework.expression.Expression;
|
||||||
|
import org.springframework.mapping.MappingFailure;
|
||||||
|
|
||||||
|
class Mapping implements MappingConfiguration {
|
||||||
|
|
||||||
|
private Expression source;
|
||||||
|
|
||||||
|
private Expression target;
|
||||||
|
|
||||||
|
private GenericConverter converter;
|
||||||
|
|
||||||
|
public Mapping(Expression source, Expression target) {
|
||||||
|
this.source = source;
|
||||||
|
this.target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSourceExpressionString() {
|
||||||
|
return this.source.getExpressionString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTargetExpressionString() {
|
||||||
|
return this.target.getExpressionString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MappingConfiguration setConverter(Converter<?, ?> converter) {
|
||||||
|
return setGenericConverter(new ConverterGenericConverter(converter));
|
||||||
|
}
|
||||||
|
|
||||||
|
public MappingConfiguration setConverterFactory(ConverterFactory<?, ?> converter) {
|
||||||
|
return setGenericConverter(new ConverterFactoryGenericConverter(converter));
|
||||||
|
}
|
||||||
|
|
||||||
|
public MappingConfiguration setGenericConverter(GenericConverter converter) {
|
||||||
|
this.converter = converter;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void map(EvaluationContext sourceContext, EvaluationContext targetContext,
|
||||||
|
Collection<MappingFailure> failures) {
|
||||||
|
try {
|
||||||
|
Object value = this.source.getValue(sourceContext);
|
||||||
|
if (this.converter != null) {
|
||||||
|
value = this.converter.convert(value, this.source.getValueTypeDescriptor(sourceContext), this.target
|
||||||
|
.getValueTypeDescriptor(targetContext));
|
||||||
|
}
|
||||||
|
this.target.setValue(targetContext, value);
|
||||||
|
} catch (Exception e) {
|
||||||
|
failures.add(new MappingFailure(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
return getSourceExpressionString().hashCode() + getTargetExpressionString().hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (!(o instanceof Mapping)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Mapping m = (Mapping) o;
|
||||||
|
return getSourceExpressionString().equals(m.getSourceExpressionString())
|
||||||
|
&& getTargetExpressionString().equals(m.getTargetExpressionString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "[Mapping<" + getSourceExpressionString() + " -> " + getTargetExpressionString() + ">]";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2009 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.mapping.support;
|
||||||
|
|
||||||
|
import org.springframework.core.convert.converter.Converter;
|
||||||
|
import org.springframework.core.convert.converter.ConverterFactory;
|
||||||
|
import org.springframework.core.convert.support.GenericConverter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A fluent API for configuring a mapping.
|
||||||
|
* @see SpelMapper#addMapping(String)
|
||||||
|
* @see SpelMapper#addMapping(String, String)
|
||||||
|
* @author Keith Donald
|
||||||
|
*/
|
||||||
|
public interface MappingConfiguration {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the type converter to use during this mapping.
|
||||||
|
* @param converter the converter
|
||||||
|
* @return this, for call chaining
|
||||||
|
*/
|
||||||
|
MappingConfiguration setConverter(Converter<?, ?> converter);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the type converter factory to use during this mapping.
|
||||||
|
* @param converter the converter factory
|
||||||
|
* @return this, for call chaining
|
||||||
|
*/
|
||||||
|
MappingConfiguration setConverterFactory(ConverterFactory<?, ?> converterFactory);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the generic converter to use during this mapping.
|
||||||
|
* A generic converter allows access to source and target field type descriptors.
|
||||||
|
* These descriptors provide additional context that can be used during type conversion.
|
||||||
|
* @param converter the generic converter
|
||||||
|
* @return this, for call chaining
|
||||||
|
*/
|
||||||
|
MappingConfiguration setGenericConverter(GenericConverter converter);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,170 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2009 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.mapping.support;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.springframework.core.convert.converter.ConverterRegistry;
|
||||||
|
import org.springframework.core.convert.support.DefaultConversionService;
|
||||||
|
import org.springframework.expression.EvaluationContext;
|
||||||
|
import org.springframework.expression.Expression;
|
||||||
|
import org.springframework.expression.ParseException;
|
||||||
|
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||||
|
import org.springframework.expression.spel.standard.SpelExpressionParserConfiguration;
|
||||||
|
import org.springframework.mapping.Mapper;
|
||||||
|
import org.springframework.mapping.MappingException;
|
||||||
|
import org.springframework.mapping.MappingFailure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A generic object mapper implementation based on the Spring Expression Language (SpEL).
|
||||||
|
* @author Keith Donald
|
||||||
|
* @see #setAutoMappingEnabled(boolean)
|
||||||
|
* @see #addMapping(String)
|
||||||
|
* @see #addMapping(String, String)
|
||||||
|
*/
|
||||||
|
public class SpelMapper implements Mapper<Object, Object> {
|
||||||
|
|
||||||
|
private static final MappableTypeFactory mappableTypeFactory = new MappableTypeFactory();
|
||||||
|
|
||||||
|
private static final SpelExpressionParser sourceExpressionParser = new SpelExpressionParser();
|
||||||
|
|
||||||
|
private static final SpelExpressionParser targetExpressionParser = new SpelExpressionParser(
|
||||||
|
SpelExpressionParserConfiguration.CreateObjectIfAttemptToReferenceNull
|
||||||
|
| SpelExpressionParserConfiguration.GrowListsOnIndexBeyondSize);
|
||||||
|
|
||||||
|
private final Set<Mapping> mappings = new LinkedHashSet<Mapping>();
|
||||||
|
|
||||||
|
private boolean autoMappingEnabled = true;
|
||||||
|
|
||||||
|
private final DefaultConversionService conversionService = new DefaultConversionService();
|
||||||
|
|
||||||
|
public void setAutoMappingEnabled(boolean autoMappingEnabled) {
|
||||||
|
this.autoMappingEnabled = autoMappingEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MappingConfiguration addMapping(String expression) {
|
||||||
|
return addMapping(expression, expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConverterRegistry getConverterRegistry() {
|
||||||
|
return conversionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MappingConfiguration addMapping(String sourceExpression, String targetExpression) {
|
||||||
|
Expression sourceExp;
|
||||||
|
try {
|
||||||
|
sourceExp = sourceExpressionParser.parseExpression(sourceExpression);
|
||||||
|
} catch (ParseException e) {
|
||||||
|
throw new IllegalArgumentException("The mapping source '" + sourceExpression
|
||||||
|
+ "' is not a parseable value expression", e);
|
||||||
|
}
|
||||||
|
Expression targetExp;
|
||||||
|
try {
|
||||||
|
targetExp = targetExpressionParser.parseExpression(targetExpression);
|
||||||
|
} catch (ParseException e) {
|
||||||
|
throw new IllegalArgumentException("The mapping target '" + targetExpression
|
||||||
|
+ "' is not a parseable property expression", e);
|
||||||
|
}
|
||||||
|
Mapping mapping = new Mapping(sourceExp, targetExp);
|
||||||
|
this.mappings.add(mapping);
|
||||||
|
return mapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void map(Object source, Object target) {
|
||||||
|
EvaluationContext sourceContext = getMappingContext(source);
|
||||||
|
EvaluationContext targetContext = getMappingContext(target);
|
||||||
|
List<MappingFailure> failures = new LinkedList<MappingFailure>();
|
||||||
|
for (Mapping mapping : this.mappings) {
|
||||||
|
mapping.map(sourceContext, targetContext, failures);
|
||||||
|
}
|
||||||
|
Set<Mapping> autoMappings = getAutoMappings(source, target);
|
||||||
|
for (Mapping mapping : autoMappings) {
|
||||||
|
mapping.map(sourceContext, targetContext, failures);
|
||||||
|
}
|
||||||
|
if (!failures.isEmpty()) {
|
||||||
|
throw new MappingException(failures);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private EvaluationContext getMappingContext(Object object) {
|
||||||
|
return mappableTypeFactory.getMappableType(object).getEvaluationContext(object, this.conversionService);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<Mapping> getAutoMappings(Object source, Object target) {
|
||||||
|
if (this.autoMappingEnabled) {
|
||||||
|
Set<Mapping> autoMappings = new LinkedHashSet<Mapping>();
|
||||||
|
Set<String> sourceFields = getMappableFields(source);
|
||||||
|
Set<String> targetFields = getMappableFields(target);
|
||||||
|
for (String field : sourceFields) {
|
||||||
|
if (!explicitlyMapped(field) && targetFields.contains(field)) {
|
||||||
|
Expression sourceExpression;
|
||||||
|
Expression targetExpression;
|
||||||
|
try {
|
||||||
|
sourceExpression = sourceExpressionParser.parseExpression(field);
|
||||||
|
} catch (ParseException e) {
|
||||||
|
throw new IllegalArgumentException("The mapping source '" + field
|
||||||
|
+ "' is not a parseable value expression", e);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
targetExpression = targetExpressionParser.parseExpression(field);
|
||||||
|
} catch (ParseException e) {
|
||||||
|
throw new IllegalArgumentException("The mapping target '" + field
|
||||||
|
+ "' is not a parseable value expression", e);
|
||||||
|
}
|
||||||
|
Mapping mapping = new Mapping(sourceExpression, targetExpression);
|
||||||
|
autoMappings.add(mapping);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return autoMappings;
|
||||||
|
} else {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> getMappableFields(Object object) {
|
||||||
|
return mappableTypeFactory.getMappableType(object).getFields(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean explicitlyMapped(String field) {
|
||||||
|
for (Mapping mapping : this.mappings) {
|
||||||
|
if (mapping.getSourceExpressionString().equals(field)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class MappableTypeFactory {
|
||||||
|
|
||||||
|
private static final MapMappableType MAP_MAPPABLE_TYPE = new MapMappableType();
|
||||||
|
|
||||||
|
private static final BeanMappableType BEAN_MAPPABLE_TYPE = new BeanMappableType();
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> MappableType<T> getMappableType(T object) {
|
||||||
|
if (object instanceof Map<?, ?>) {
|
||||||
|
return (MappableType<T>) MAP_MAPPABLE_TYPE;
|
||||||
|
} else {
|
||||||
|
return (MappableType<T>) BEAN_MAPPABLE_TYPE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,370 @@
|
||||||
|
package org.springframework.mapping.support;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.core.convert.converter.Converter;
|
||||||
|
import org.springframework.mapping.MappingException;
|
||||||
|
|
||||||
|
public class SpelMapperTests {
|
||||||
|
|
||||||
|
private SpelMapper mapper = new SpelMapper();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mapAutomatic() {
|
||||||
|
Map<String, Object> source = new HashMap<String, Object>();
|
||||||
|
source.put("name", "Keith");
|
||||||
|
source.put("age", 31);
|
||||||
|
|
||||||
|
Person target = new Person();
|
||||||
|
|
||||||
|
mapper.map(source, target);
|
||||||
|
|
||||||
|
assertEquals("Keith", target.name);
|
||||||
|
assertEquals(31, target.age);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mapExplicit() throws MappingException {
|
||||||
|
mapper.setAutoMappingEnabled(false);
|
||||||
|
mapper.addMapping("name");
|
||||||
|
|
||||||
|
Map<String, Object> source = new HashMap<String, Object>();
|
||||||
|
source.put("name", "Keith");
|
||||||
|
source.put("age", 31);
|
||||||
|
|
||||||
|
Person target = new Person();
|
||||||
|
|
||||||
|
mapper.map(source, target);
|
||||||
|
|
||||||
|
assertEquals("Keith", target.name);
|
||||||
|
assertEquals(0, target.age);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mapAutomaticWithExplictOverrides() {
|
||||||
|
mapper.addMapping("test", "age");
|
||||||
|
|
||||||
|
Map<String, Object> source = new HashMap<String, Object>();
|
||||||
|
source.put("name", "Keith");
|
||||||
|
source.put("test", "3");
|
||||||
|
source.put("favoriteSport", "FOOTBALL");
|
||||||
|
|
||||||
|
Person target = new Person();
|
||||||
|
|
||||||
|
mapper.map(source, target);
|
||||||
|
|
||||||
|
assertEquals("Keith", target.name);
|
||||||
|
assertEquals(3, target.age);
|
||||||
|
assertEquals(Sport.FOOTBALL, target.favoriteSport);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mapSameSourceFieldToMultipleTargets() {
|
||||||
|
mapper.addMapping("test", "name");
|
||||||
|
mapper.addMapping("test", "favoriteSport");
|
||||||
|
|
||||||
|
Map<String, Object> source = new HashMap<String, Object>();
|
||||||
|
source.put("test", "FOOTBALL");
|
||||||
|
|
||||||
|
Person target = new Person();
|
||||||
|
|
||||||
|
mapper.map(source, target);
|
||||||
|
|
||||||
|
assertEquals("FOOTBALL", target.name);
|
||||||
|
assertEquals(0, target.age);
|
||||||
|
assertEquals(Sport.FOOTBALL, target.favoriteSport);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mapBean() {
|
||||||
|
PersonDto source = new PersonDto();
|
||||||
|
source.setFullName("Keith Donald");
|
||||||
|
source.setAge("31");
|
||||||
|
source.setSport("FOOTBALL");
|
||||||
|
|
||||||
|
Person target = new Person();
|
||||||
|
|
||||||
|
mapper.addMapping("fullName", "name");
|
||||||
|
mapper.addMapping("sport", "favoriteSport");
|
||||||
|
|
||||||
|
mapper.map(source, target);
|
||||||
|
|
||||||
|
assertEquals("Keith Donald", target.name);
|
||||||
|
assertEquals(31, target.age);
|
||||||
|
assertEquals(Sport.FOOTBALL, target.favoriteSport);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mapBeanNested() {
|
||||||
|
PersonDto source = new PersonDto();
|
||||||
|
source.setFullName("Keith Donald");
|
||||||
|
source.setAge("31");
|
||||||
|
source.setSport("FOOTBALL");
|
||||||
|
|
||||||
|
Person target = new Person();
|
||||||
|
|
||||||
|
mapper.addMapping("fullName", "nested.fullName");
|
||||||
|
mapper.addMapping("age", "nested.age");
|
||||||
|
mapper.addMapping("sport", "nested.sport");
|
||||||
|
|
||||||
|
mapper.map(source, target);
|
||||||
|
|
||||||
|
assertEquals("Keith Donald", target.getNested().getFullName());
|
||||||
|
assertEquals("31", target.nested.age);
|
||||||
|
assertEquals("FOOTBALL", target.nested.sport);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mapList() {
|
||||||
|
PersonDto source = new PersonDto();
|
||||||
|
List<String> sports = new ArrayList<String>();
|
||||||
|
sports.add("FOOTBALL");
|
||||||
|
sports.add("BASKETBALL");
|
||||||
|
source.setSports(sports);
|
||||||
|
|
||||||
|
Person target = new Person();
|
||||||
|
|
||||||
|
mapper.setAutoMappingEnabled(false);
|
||||||
|
mapper.addMapping("sports", "favoriteSports");
|
||||||
|
|
||||||
|
mapper.map(source, target);
|
||||||
|
|
||||||
|
assertEquals(Sport.FOOTBALL, target.favoriteSports.get(0));
|
||||||
|
assertEquals(Sport.BASKETBALL, target.favoriteSports.get(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mapMap() {
|
||||||
|
PersonDto source = new PersonDto();
|
||||||
|
Map<String, String> friendRankings = new HashMap<String, String>();
|
||||||
|
friendRankings.put("Keri", "1");
|
||||||
|
friendRankings.put("Alf", "2");
|
||||||
|
source.setFriendRankings(friendRankings);
|
||||||
|
|
||||||
|
Person target = new Person();
|
||||||
|
|
||||||
|
mapper.setAutoMappingEnabled(false);
|
||||||
|
mapper.addMapping("friendRankings", "friendRankings");
|
||||||
|
mapper.getConverterRegistry().addConverter(new Converter<String, Person>() {
|
||||||
|
public Person convert(String source) {
|
||||||
|
return new Person(source);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mapper.map(source, target);
|
||||||
|
|
||||||
|
assertEquals(new Integer(1), target.friendRankings.get(new Person("Keri")));
|
||||||
|
assertEquals(new Integer(2), target.friendRankings.get(new Person("Alf")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mapFieldConverter() {
|
||||||
|
Map<String, Object> source = new HashMap<String, Object>();
|
||||||
|
source.put("name", "Keith Donald");
|
||||||
|
source.put("age", 31);
|
||||||
|
|
||||||
|
Person target = new Person();
|
||||||
|
|
||||||
|
mapper.addMapping("name").setConverter(new Converter<String, String>() {
|
||||||
|
public String convert(String source) {
|
||||||
|
String[] names = source.split(" ");
|
||||||
|
return names[0] + " P. " + names[1];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mapper.map(source, target);
|
||||||
|
|
||||||
|
assertEquals("Keith P. Donald", target.name);
|
||||||
|
assertEquals(31, target.age);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mapFailure() {
|
||||||
|
Map<String, Object> source = new HashMap<String, Object>();
|
||||||
|
source.put("name", "Keith");
|
||||||
|
source.put("age", "bogus");
|
||||||
|
Person target = new Person();
|
||||||
|
try {
|
||||||
|
mapper.map(source, target);
|
||||||
|
} catch (MappingException e) {
|
||||||
|
assertEquals(1, e.getMappingFailureCount());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PersonDto {
|
||||||
|
|
||||||
|
private String fullName;
|
||||||
|
|
||||||
|
private String age;
|
||||||
|
|
||||||
|
private String sport;
|
||||||
|
|
||||||
|
private List<String> sports;
|
||||||
|
|
||||||
|
private Map<String, String> friendRankings;
|
||||||
|
|
||||||
|
private NestedDto nestedDto;
|
||||||
|
|
||||||
|
public String getFullName() {
|
||||||
|
return fullName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFullName(String fullName) {
|
||||||
|
this.fullName = fullName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAge() {
|
||||||
|
return age;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAge(String age) {
|
||||||
|
this.age = age;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSport() {
|
||||||
|
return sport;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSport(String sport) {
|
||||||
|
this.sport = sport;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getSports() {
|
||||||
|
return sports;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSports(List<String> sports) {
|
||||||
|
this.sports = sports;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getFriendRankings() {
|
||||||
|
return friendRankings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFriendRankings(Map<String, String> friendRankings) {
|
||||||
|
this.friendRankings = friendRankings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NestedDto getNestedDto() {
|
||||||
|
return nestedDto;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNestedDto(NestedDto nestedDto) {
|
||||||
|
this.nestedDto = nestedDto;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class NestedDto {
|
||||||
|
|
||||||
|
private String foo;
|
||||||
|
|
||||||
|
public String getFoo() {
|
||||||
|
return foo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Person {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private int age;
|
||||||
|
|
||||||
|
private Sport favoriteSport;
|
||||||
|
|
||||||
|
private PersonDto nested;
|
||||||
|
|
||||||
|
// private Person cyclic;
|
||||||
|
|
||||||
|
private List<Sport> favoriteSports;
|
||||||
|
|
||||||
|
private Map<Person, Integer> friendRankings;
|
||||||
|
|
||||||
|
public Person() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Person(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAge() {
|
||||||
|
return age;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAge(int age) {
|
||||||
|
this.age = age;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Sport getFavoriteSport() {
|
||||||
|
return favoriteSport;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFavoriteSport(Sport favoriteSport) {
|
||||||
|
this.favoriteSport = favoriteSport;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PersonDto getNested() {
|
||||||
|
return nested;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNested(PersonDto nested) {
|
||||||
|
this.nested = nested;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
public Person getCyclic() {
|
||||||
|
return cyclic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCyclic(Person cyclic) {
|
||||||
|
this.cyclic = cyclic;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
public List<Sport> getFavoriteSports() {
|
||||||
|
return favoriteSports;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFavoriteSports(List<Sport> favoriteSports) {
|
||||||
|
this.favoriteSports = favoriteSports;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Person, Integer> getFriendRankings() {
|
||||||
|
return friendRankings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFriendRankings(Map<Person, Integer> friendRankings) {
|
||||||
|
this.friendRankings = friendRankings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
return name.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (!(o instanceof Person)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Person p = (Person) o;
|
||||||
|
return name.equals(p.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Sport {
|
||||||
|
FOOTBALL, BASKETBALL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.springframework.core.convert.support;
|
||||||
|
|
||||||
|
import org.springframework.core.convert.TypeDescriptor;
|
||||||
|
import org.springframework.core.convert.converter.ConverterFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapts a ConverterFactory to the uniform GenericConverter interface.
|
||||||
|
* @author Keith Donald
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public final class ConverterFactoryGenericConverter implements GenericConverter {
|
||||||
|
|
||||||
|
private final ConverterFactory converterFactory;
|
||||||
|
|
||||||
|
public ConverterFactoryGenericConverter(ConverterFactory converterFactory) {
|
||||||
|
this.converterFactory = converterFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||||
|
return this.converterFactory.getConverter(targetType.getObjectType()).convert(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2009 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.core.convert.support;
|
||||||
|
|
||||||
|
import org.springframework.core.convert.TypeDescriptor;
|
||||||
|
import org.springframework.core.convert.converter.Converter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapts a Converter to the uniform GenericConverter interface.
|
||||||
|
* @author Keith Donald
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public final class ConverterGenericConverter implements GenericConverter {
|
||||||
|
|
||||||
|
private final Converter converter;
|
||||||
|
|
||||||
|
public ConverterGenericConverter(Converter converter) {
|
||||||
|
this.converter = converter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||||
|
return this.converter.convert(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -130,7 +130,7 @@ public class GenericConversionService implements ConversionService, ConverterReg
|
||||||
}
|
}
|
||||||
Class sourceType = typeInfo[0];
|
Class sourceType = typeInfo[0];
|
||||||
Class targetType = typeInfo[1];
|
Class targetType = typeInfo[1];
|
||||||
getSourceMap(sourceType).put(targetType, new ConverterAdapter(converter));
|
getSourceMap(sourceType).put(targetType, new ConverterGenericConverter(converter));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addConverterFactory(ConverterFactory<?, ?> converterFactory) {
|
public void addConverterFactory(ConverterFactory<?, ?> converterFactory) {
|
||||||
|
|
@ -141,7 +141,7 @@ public class GenericConversionService implements ConversionService, ConverterReg
|
||||||
}
|
}
|
||||||
Class sourceType = typeInfo[0];
|
Class sourceType = typeInfo[0];
|
||||||
Class targetType = typeInfo[1];
|
Class targetType = typeInfo[1];
|
||||||
getSourceMap(sourceType).put(targetType, new ConverterFactoryAdapter(converterFactory));
|
getSourceMap(sourceType).put(targetType, new ConverterFactoryGenericConverter(converterFactory));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeConvertible(Class<?> sourceType, Class<?> targetType) {
|
public void removeConvertible(Class<?> sourceType, Class<?> targetType) {
|
||||||
|
|
@ -245,7 +245,7 @@ public class GenericConversionService implements ConversionService, ConverterReg
|
||||||
|
|
||||||
// internal helpers
|
// internal helpers
|
||||||
|
|
||||||
private Class[] getRequiredTypeInfo(Object converter, Class ifc) {
|
private Class[] getRequiredTypeInfo(Object converter, Class genericIfc) {
|
||||||
Class[] typeInfo = new Class[2];
|
Class[] typeInfo = new Class[2];
|
||||||
if (converter instanceof ConverterInfo) {
|
if (converter instanceof ConverterInfo) {
|
||||||
ConverterInfo info = (ConverterInfo) converter;
|
ConverterInfo info = (ConverterInfo) converter;
|
||||||
|
|
@ -254,7 +254,7 @@ public class GenericConversionService implements ConversionService, ConverterReg
|
||||||
return typeInfo;
|
return typeInfo;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return GenericTypeResolver.resolveTypeArguments(converter.getClass(), ifc);
|
return GenericTypeResolver.resolveTypeArguments(converter.getClass(), genericIfc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -370,34 +370,4 @@ public class GenericConversionService implements ConversionService, ConverterReg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class ConverterAdapter implements GenericConverter {
|
|
||||||
|
|
||||||
private Converter converter;
|
|
||||||
|
|
||||||
public ConverterAdapter(Converter converter) {
|
|
||||||
this.converter = converter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
|
||||||
return this.converter.convert(source);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static class ConverterFactoryAdapter implements GenericConverter {
|
|
||||||
|
|
||||||
private ConverterFactory converterFactory;
|
|
||||||
|
|
||||||
public ConverterFactoryAdapter(ConverterFactory converterFactory) {
|
|
||||||
this.converterFactory = converterFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
|
||||||
return this.converterFactory.getConverter(targetType.getObjectType()).convert(source);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue