enhanced mapper subsystem
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
package org.springframework.binding.expression;
|
||||
|
||||
/**
|
||||
* An evaluation exception indicating a expression that references a property failed to evaluate because the property
|
||||
* could not be found.
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class PropertyNotFoundException extends EvaluationException {
|
||||
|
||||
/**
|
||||
* Creates a new property not found exception
|
||||
* @param evaluationAttempt the evaluaion attempt details
|
||||
* @param cause root cause of the failure
|
||||
*/
|
||||
public PropertyNotFoundException(EvaluationAttempt evaluationAttempt, Throwable cause) {
|
||||
super(evaluationAttempt, cause);
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import javax.el.ValueExpression;
|
||||
import org.springframework.binding.expression.EvaluationAttempt;
|
||||
import org.springframework.binding.expression.EvaluationException;
|
||||
import org.springframework.binding.expression.Expression;
|
||||
import org.springframework.binding.expression.PropertyNotFoundException;
|
||||
import org.springframework.binding.expression.SetValueAttempt;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -46,8 +47,10 @@ public class ELExpression implements Expression {
|
||||
throw new EvaluationException(new EvaluationAttempt(this, context), null);
|
||||
}
|
||||
return result;
|
||||
} catch (ELException ex) {
|
||||
throw new EvaluationException(new EvaluationAttempt(this, context), ex);
|
||||
} catch (javax.el.PropertyNotFoundException e) {
|
||||
throw new PropertyNotFoundException(new EvaluationAttempt(this, context), e);
|
||||
} catch (ELException e) {
|
||||
throw new EvaluationException(new EvaluationAttempt(this, context), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +61,8 @@ public class ELExpression implements Expression {
|
||||
if (!ctx.isPropertyResolved()) {
|
||||
throw new EvaluationException(new SetValueAttempt(this, context, value), null);
|
||||
}
|
||||
} catch (javax.el.PropertyNotFoundException e) {
|
||||
throw new PropertyNotFoundException(new EvaluationAttempt(this, context), e);
|
||||
} catch (ELException ex) {
|
||||
throw new EvaluationException(new EvaluationAttempt(this, context), ex);
|
||||
}
|
||||
@@ -67,6 +72,8 @@ public class ELExpression implements Expression {
|
||||
ELContext ctx = elContextFactory.getELContext(context);
|
||||
try {
|
||||
return valueExpression.getType(ctx);
|
||||
} catch (javax.el.PropertyNotFoundException e) {
|
||||
throw new PropertyNotFoundException(new EvaluationAttempt(this, context), e);
|
||||
} catch (ELException ex) {
|
||||
throw new EvaluationException(new EvaluationAttempt(this, context), ex);
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004-2007 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.binding.mapping;
|
||||
|
||||
/**
|
||||
* A lightweight service interface for mapping between two attribute sources.
|
||||
* <p>
|
||||
* Implementations of this interface are expected to encapsulate the mapping configuration information as well as the
|
||||
* logic to act on it to perform mapping between a given source and target attribute source.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface AttributeMapper {
|
||||
|
||||
/**
|
||||
* Map data from a source object to a target object.
|
||||
* @param source the source
|
||||
* @param target the target
|
||||
* @param context the mapping context
|
||||
* @throws AttributeMappingException if errors occurred during the mapping process
|
||||
*/
|
||||
public void map(Object source, Object target, MappingContext context) throws AttributeMappingException;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package org.springframework.binding.mapping;
|
||||
|
||||
public class AttributeMappingException extends RuntimeException {
|
||||
|
||||
}
|
||||
@@ -1,32 +1,32 @@
|
||||
/*
|
||||
* Copyright 2004-2007 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.binding.mapping;
|
||||
|
||||
/**
|
||||
* Thrown when a required mapping could not be performed.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class RequiredMappingException extends IllegalStateException {
|
||||
|
||||
/**
|
||||
* Create a new required mapping exception.
|
||||
* @param message a descriptive message
|
||||
*/
|
||||
public RequiredMappingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright 2004-2007 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.binding.mapping;
|
||||
|
||||
/**
|
||||
* Maps state between two objects.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface Mapper {
|
||||
|
||||
/**
|
||||
* Map state from a source object to a target object.
|
||||
* @param source the source
|
||||
* @param target the target
|
||||
* @return results of the mapping transaction
|
||||
*/
|
||||
public MappingResults map(Object source, Object target);
|
||||
}
|
||||
@@ -1,192 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004-2007 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.binding.mapping;
|
||||
|
||||
import org.springframework.binding.convert.ConversionService;
|
||||
import org.springframework.binding.convert.ConversionExecutor;
|
||||
import org.springframework.binding.convert.support.DefaultConversionService;
|
||||
import org.springframework.binding.convert.support.RuntimeBindingConversionExecutor;
|
||||
import org.springframework.binding.expression.Expression;
|
||||
import org.springframework.binding.expression.ExpressionParser;
|
||||
import org.springframework.binding.expression.support.CollectionAddingExpression;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A stateful builder that builds {@link Mapping} objects. Designed for convenience to build mappings in a clear,
|
||||
* readable manner.
|
||||
* <p>
|
||||
* Example usage:
|
||||
*
|
||||
* <pre>
|
||||
* MappingBuilder mapping = new MappingBuilder();
|
||||
* Mapping result = mapping.source("foo").target("bar").from(String.class).to(Long.class).value();
|
||||
* </pre>
|
||||
*
|
||||
* Calling the {@link #value()} result method clears out this builder's state so it can be reused to build another
|
||||
* mapping.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Erwin Vervaet
|
||||
*/
|
||||
public class MappingBuilder {
|
||||
|
||||
/**
|
||||
* The expression string parser.
|
||||
*/
|
||||
private ExpressionParser expressionParser;
|
||||
|
||||
/**
|
||||
* The conversion service for applying type conversions.
|
||||
*/
|
||||
private ConversionService conversionService = new DefaultConversionService();
|
||||
|
||||
/**
|
||||
* The source mapping expression.
|
||||
*/
|
||||
private Expression sourceExpression;
|
||||
|
||||
/**
|
||||
* The target mapping settable expression.
|
||||
*/
|
||||
private Expression targetExpression;
|
||||
|
||||
/**
|
||||
* The type of the object returned by evaluating the source expression.
|
||||
*/
|
||||
private Class sourceType;
|
||||
|
||||
/**
|
||||
* The type of the property settable by the target expression.
|
||||
*/
|
||||
private Class targetType;
|
||||
|
||||
/**
|
||||
* Whether or not the built mapping is a required mapping.
|
||||
*/
|
||||
private boolean required;
|
||||
|
||||
/**
|
||||
* Creates a mapping builder that uses the expression parser to parse attribute mapping expressions.
|
||||
* @param expressionParser the expression parser
|
||||
*/
|
||||
public MappingBuilder(ExpressionParser expressionParser) {
|
||||
Assert.notNull(expressionParser, "The expression parser is required");
|
||||
this.expressionParser = expressionParser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the conversion service that will convert the object returned by evaluating the source expression to the
|
||||
* {@link #to(Class)} type if necessary.
|
||||
* @param conversionService the conversion service
|
||||
*/
|
||||
public void setConversionService(ConversionService conversionService) {
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the source expression of the mapping built by this builder.
|
||||
* @param expressionString the expression string
|
||||
* @return this, to support call-chaining
|
||||
*/
|
||||
public MappingBuilder source(String expressionString) {
|
||||
sourceExpression = expressionParser.parseExpression(expressionString, null);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the target property expression of the mapping built by this builder.
|
||||
* @param expressionString the expression string
|
||||
* @return this, to support call-chaining
|
||||
*/
|
||||
public MappingBuilder target(String expressionString) {
|
||||
targetExpression = expressionParser.parseExpression(expressionString, null);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the target collection of the mapping built by this builder.
|
||||
* @param expressionString the expression string, resolving a collection
|
||||
* @return this, to support call-chaining
|
||||
*/
|
||||
public MappingBuilder targetCollection(String expressionString) {
|
||||
targetExpression = new CollectionAddingExpression(expressionParser.parseExpression(expressionString, null));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the expected type of the object returned by evaluating the source expression. Used in conjunction with
|
||||
* {@link #to(Class)} to perform a type conversion during the mapping process.
|
||||
* @param sourceType the source type
|
||||
* @return this, to support call-chaining
|
||||
*/
|
||||
public MappingBuilder from(Class sourceType) {
|
||||
this.sourceType = sourceType;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the target type of the property writeable by the target expression.
|
||||
* @param targetType the target type
|
||||
* @return this, to support call-chaining
|
||||
*/
|
||||
public MappingBuilder to(Class targetType) {
|
||||
this.targetType = targetType;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the mapping to be built a "required" mapping.
|
||||
* @return this, to support call-chaining
|
||||
*/
|
||||
public MappingBuilder required() {
|
||||
this.required = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The logical GoF builder getResult method, returning a fully constructed Mapping from the configured pieces. Once
|
||||
* called, the state of this builder is nulled out to support building a new mapping object again.
|
||||
* @return the mapping result
|
||||
*/
|
||||
public Mapping value() {
|
||||
Assert.notNull(sourceExpression, "The source expression must be set at a minimum");
|
||||
if (targetExpression == null) {
|
||||
targetExpression = sourceExpression;
|
||||
}
|
||||
ConversionExecutor typeConverter = null;
|
||||
if (targetType != null) {
|
||||
if (sourceType != null) {
|
||||
typeConverter = conversionService.getConversionExecutor(sourceType, targetType);
|
||||
} else {
|
||||
typeConverter = new RuntimeBindingConversionExecutor(targetType, conversionService);
|
||||
}
|
||||
}
|
||||
Mapping result = new Mapping(sourceExpression, targetExpression, typeConverter, required);
|
||||
reset();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset this mapping builder.
|
||||
*/
|
||||
public void reset() {
|
||||
sourceExpression = null;
|
||||
targetExpression = null;
|
||||
sourceType = null;
|
||||
targetType = null;
|
||||
required = false;
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004-2007 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.binding.mapping;
|
||||
|
||||
import org.springframework.binding.message.MessageContext;
|
||||
|
||||
/**
|
||||
* A context object with two main responsibities:
|
||||
* <ol>
|
||||
* <li>Exposing information to a mapper to influence a mapping attempt.
|
||||
* <li>Providing operations for recording progress or errors during the mapping process.
|
||||
* </ol>
|
||||
* Empty for now; subclasses may define their own custom context behavior accessible by a mapper with a downcast.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface MappingContext {
|
||||
|
||||
/**
|
||||
* Returns the message context to use to record errors during the mapping process.
|
||||
* @return the message context
|
||||
*/
|
||||
public MessageContext getMessageContext();
|
||||
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package org.springframework.binding.mapping;
|
||||
|
||||
import org.springframework.binding.message.MessageContext;
|
||||
|
||||
public class MappingContextImpl implements MappingContext {
|
||||
|
||||
private MessageContext messageContext;
|
||||
|
||||
public MappingContextImpl(MessageContext messageContext) {
|
||||
this.messageContext = messageContext;
|
||||
}
|
||||
|
||||
public MessageContext getMessageContext() {
|
||||
return messageContext;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.springframework.binding.mapping;
|
||||
|
||||
public class MappingResult {
|
||||
|
||||
private Mapping mapping;
|
||||
|
||||
private Result result;
|
||||
|
||||
public MappingResult(Mapping mapping, Result result) {
|
||||
this.mapping = mapping;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public Mapping getMapping() {
|
||||
return mapping;
|
||||
}
|
||||
|
||||
public Result getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.springframework.binding.mapping;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface MappingResults {
|
||||
|
||||
public Object getSource();
|
||||
|
||||
public Object getTarget();
|
||||
|
||||
public List getAllResults();
|
||||
|
||||
public boolean hasErrorResults();
|
||||
|
||||
public List getErrorResults();
|
||||
|
||||
public List getResults(MappingResultsCriteria criteria);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package org.springframework.binding.mapping;
|
||||
|
||||
public interface MappingResultsCriteria {
|
||||
public boolean test(MappingResult result);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.springframework.binding.mapping;
|
||||
|
||||
public abstract class Result {
|
||||
public abstract Object getOriginalValue();
|
||||
|
||||
public abstract Object getMappedValue();
|
||||
|
||||
public abstract boolean isError();
|
||||
|
||||
public abstract String getErrorCode();
|
||||
}
|
||||
@@ -13,13 +13,16 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.binding.mapping;
|
||||
package org.springframework.binding.mapping.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.binding.convert.ConversionService;
|
||||
import org.springframework.binding.mapping.Mapper;
|
||||
import org.springframework.binding.mapping.Mapping;
|
||||
import org.springframework.binding.mapping.MappingResults;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
|
||||
/**
|
||||
@@ -29,34 +32,33 @@ import org.springframework.core.style.ToStringCreator;
|
||||
* @author Keith Donald
|
||||
* @author Colin Sampaleanu
|
||||
*/
|
||||
public class DefaultAttributeMapper implements AttributeMapper {
|
||||
public class DefaultMapper implements Mapper {
|
||||
|
||||
/**
|
||||
* The ordered list of mappings to apply.
|
||||
*/
|
||||
private List mappings = new LinkedList();
|
||||
|
||||
private ConversionService conversionService;
|
||||
|
||||
public ConversionService getConversionService() {
|
||||
return conversionService;
|
||||
}
|
||||
|
||||
public void setConversionService(ConversionService conversionService) {
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a mapping to this mapper.
|
||||
* @param mapping the mapping to add
|
||||
* @return this, to support convenient call chaining
|
||||
*/
|
||||
public DefaultAttributeMapper addMapping(Mapping mapping) {
|
||||
public DefaultMapper addMapping(DefaultMapping mapping) {
|
||||
mappings.add(mapping);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a set of mappings.
|
||||
* @param mappings the mappings
|
||||
*/
|
||||
public void addMappings(Mapping[] mappings) {
|
||||
if (mappings == null) {
|
||||
return;
|
||||
}
|
||||
this.mappings.addAll(Arrays.asList(mappings));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this mapper's list of mappings.
|
||||
* @return the list of mappings
|
||||
@@ -65,21 +67,14 @@ public class DefaultAttributeMapper implements AttributeMapper {
|
||||
return (Mapping[]) mappings.toArray(new Mapping[mappings.size()]);
|
||||
}
|
||||
|
||||
public void map(Object source, Object target, MappingContext context) throws AttributeMappingException {
|
||||
boolean mappingFailure = false;
|
||||
if (mappings != null) {
|
||||
Iterator it = mappings.iterator();
|
||||
while (it.hasNext()) {
|
||||
Mapping mapping = (Mapping) it.next();
|
||||
boolean result = mapping.map(source, target, context);
|
||||
if (!result && !mappingFailure) {
|
||||
mappingFailure = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mappingFailure) {
|
||||
throw new AttributeMappingException();
|
||||
public MappingResults map(Object source, Object target) {
|
||||
DefaultMappingContext context = new DefaultMappingContext(source, target, conversionService);
|
||||
Iterator it = mappings.iterator();
|
||||
while (it.hasNext()) {
|
||||
DefaultMapping mapping = (DefaultMapping) it.next();
|
||||
mapping.map(context);
|
||||
}
|
||||
return context.toResult();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright 2004-2007 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.binding.mapping.impl;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.binding.convert.ConversionException;
|
||||
import org.springframework.binding.convert.ConversionExecutor;
|
||||
import org.springframework.binding.convert.ConversionService;
|
||||
import org.springframework.binding.expression.EvaluationException;
|
||||
import org.springframework.binding.expression.Expression;
|
||||
import org.springframework.binding.mapping.Mapping;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A single mapping definition, encapsulating the information necessary to map the result of evaluating an expression on
|
||||
* a source object to a property on a target object, optionally applying a type conversion during the mapping process.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class DefaultMapping implements Mapping {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(DefaultMapping.class);
|
||||
|
||||
/**
|
||||
* The source expression to evaluate against a source object to map from.
|
||||
*/
|
||||
private final Expression sourceExpression;
|
||||
|
||||
/**
|
||||
* The target expression to set on a target object to map to.
|
||||
*/
|
||||
private final Expression targetExpression;
|
||||
|
||||
/**
|
||||
* Whether or not this is a required mapping; if true, the source expression must return a non-null value.
|
||||
*/
|
||||
private boolean required;
|
||||
|
||||
/**
|
||||
* A specific type conversion routine to apply during the mapping process.
|
||||
*/
|
||||
private ConversionExecutor typeConverter;
|
||||
|
||||
/**
|
||||
* Creates a new mapping.
|
||||
* @param sourceExpression the source expression
|
||||
* @param targetExpression the target expression
|
||||
*/
|
||||
public DefaultMapping(Expression sourceExpression, Expression targetExpression) {
|
||||
Assert.notNull(sourceExpression, "The source expression is required");
|
||||
Assert.notNull(targetExpression, "The target expression is required");
|
||||
this.sourceExpression = sourceExpression;
|
||||
this.targetExpression = targetExpression;
|
||||
}
|
||||
|
||||
// implementing mapping
|
||||
|
||||
public Expression getSourceExpression() {
|
||||
return sourceExpression;
|
||||
}
|
||||
|
||||
public Expression getTargetExpression() {
|
||||
return targetExpression;
|
||||
}
|
||||
|
||||
public boolean isRequired() {
|
||||
return required;
|
||||
}
|
||||
|
||||
// optional impl getters/setters
|
||||
|
||||
public ConversionExecutor getTypeConverter() {
|
||||
return typeConverter;
|
||||
}
|
||||
|
||||
public void setTypeConverter(ConversionExecutor typeConverter) {
|
||||
this.typeConverter = typeConverter;
|
||||
}
|
||||
|
||||
public void setRequired(boolean required) {
|
||||
this.required = required;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute this mapping.
|
||||
* @param context the mapping context
|
||||
*/
|
||||
public void map(MappingContext context) {
|
||||
context.setCurrentMapping(this);
|
||||
Object sourceValue;
|
||||
try {
|
||||
sourceValue = sourceExpression.getValue(context.getSource());
|
||||
} catch (EvaluationException e) {
|
||||
context.setSourceAccessError(e);
|
||||
return;
|
||||
}
|
||||
if (required && (sourceValue == null || isEmptyString(sourceValue))) {
|
||||
context.setRequiredErrorResult(sourceValue);
|
||||
return;
|
||||
}
|
||||
Object targetValue = sourceValue;
|
||||
if (sourceValue != null) {
|
||||
if (typeConverter != null) {
|
||||
try {
|
||||
targetValue = typeConverter.execute(targetValue);
|
||||
} catch (ConversionException e) {
|
||||
context.setTypeConversionErrorResult(sourceValue, e.getTargetClass());
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
ConversionService conversionService = context.getConversionService();
|
||||
if (conversionService != null) {
|
||||
Class targetType;
|
||||
try {
|
||||
targetType = targetExpression.getValueType(context.getTarget());
|
||||
} catch (EvaluationException e) {
|
||||
context.setTargetAccessError(sourceValue, e);
|
||||
return;
|
||||
}
|
||||
if (targetType != null && !targetType.isInstance(targetValue)) {
|
||||
try {
|
||||
ConversionExecutor typeConverter = conversionService.getConversionExecutor(sourceValue
|
||||
.getClass(), targetType);
|
||||
targetValue = typeConverter.execute(sourceValue);
|
||||
} catch (ConversionException e) {
|
||||
context.setTypeConversionErrorResult(sourceValue, e.getTargetClass());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Mapping '" + sourceExpression + "' value [" + sourceValue + "] to target '"
|
||||
+ targetExpression + "'; setting target value to [" + targetValue + "]");
|
||||
}
|
||||
try {
|
||||
targetExpression.setValue(context.getTarget(), targetValue);
|
||||
context.setSuccessResult(sourceValue, targetValue);
|
||||
} catch (EvaluationException e) {
|
||||
context.setTargetAccessError(sourceValue, e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isEmptyString(Object sourceValue) {
|
||||
if (sourceValue instanceof CharSequence) {
|
||||
return ((CharSequence) sourceValue).length() == 0;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof DefaultMapping)) {
|
||||
return false;
|
||||
}
|
||||
DefaultMapping other = (DefaultMapping) o;
|
||||
return sourceExpression.equals(other.sourceExpression) && targetExpression.equals(other.targetExpression);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return sourceExpression.hashCode() + targetExpression.hashCode();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return new ToStringCreator(this).append(sourceExpression + " -> " + targetExpression).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package org.springframework.binding.mapping.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.binding.convert.ConversionService;
|
||||
import org.springframework.binding.expression.EvaluationException;
|
||||
import org.springframework.binding.mapping.Mapping;
|
||||
import org.springframework.binding.mapping.MappingResult;
|
||||
import org.springframework.binding.mapping.MappingResults;
|
||||
import org.springframework.binding.mapping.results.RequiredError;
|
||||
import org.springframework.binding.mapping.results.SourceAccessError;
|
||||
import org.springframework.binding.mapping.results.Success;
|
||||
import org.springframework.binding.mapping.results.TargetAccessError;
|
||||
import org.springframework.binding.mapping.results.TypeConversionError;
|
||||
|
||||
class DefaultMappingContext implements MappingContext {
|
||||
|
||||
private Object source;
|
||||
|
||||
private Object target;
|
||||
|
||||
private Mapping currentMapping;
|
||||
|
||||
private List mappingResults;
|
||||
|
||||
private ConversionService conversionService;
|
||||
|
||||
public DefaultMappingContext(Object source, Object target, ConversionService conversionService) {
|
||||
this.source = source;
|
||||
this.target = target;
|
||||
this.conversionService = conversionService;
|
||||
this.mappingResults = new ArrayList();
|
||||
}
|
||||
|
||||
public Object getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
public Object getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
public ConversionService getConversionService() {
|
||||
return conversionService;
|
||||
}
|
||||
|
||||
public void setCurrentMapping(Mapping mapping) {
|
||||
if (this.currentMapping != null) {
|
||||
throw new IllegalStateException("The current mapping has not finished yet");
|
||||
}
|
||||
this.currentMapping = mapping;
|
||||
}
|
||||
|
||||
public void setSuccessResult(Object originalValue, Object mappedValue) {
|
||||
mappingResults.add(new MappingResult(currentMapping, new Success(originalValue, mappedValue)));
|
||||
currentMapping = null;
|
||||
}
|
||||
|
||||
public void setRequiredErrorResult(Object originalValue) {
|
||||
mappingResults.add(new MappingResult(currentMapping, new RequiredError(originalValue)));
|
||||
this.currentMapping = null;
|
||||
}
|
||||
|
||||
public void setTypeConversionErrorResult(Object originalValue, Class targetType) {
|
||||
mappingResults.add(new MappingResult(currentMapping, new TypeConversionError(originalValue, targetType)));
|
||||
this.currentMapping = null;
|
||||
}
|
||||
|
||||
public void setSourceAccessError(EvaluationException error) {
|
||||
mappingResults.add(new MappingResult(currentMapping, new SourceAccessError(error)));
|
||||
this.currentMapping = null;
|
||||
}
|
||||
|
||||
public void setTargetAccessError(Object originalValue, EvaluationException error) {
|
||||
mappingResults.add(new MappingResult(currentMapping, new TargetAccessError(originalValue, error)));
|
||||
this.currentMapping = null;
|
||||
}
|
||||
|
||||
public MappingResults toResult() {
|
||||
return new DefaultMappingResults(source, target, mappingResults);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package org.springframework.binding.mapping.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.binding.mapping.MappingResult;
|
||||
import org.springframework.binding.mapping.MappingResults;
|
||||
import org.springframework.binding.mapping.MappingResultsCriteria;
|
||||
|
||||
public class DefaultMappingResults implements MappingResults {
|
||||
|
||||
private Object source;
|
||||
|
||||
private Object target;
|
||||
|
||||
private List mappingResults;
|
||||
|
||||
public DefaultMappingResults(Object source, Object target, List mappingResults) {
|
||||
this.source = source;
|
||||
this.target = target;
|
||||
this.mappingResults = mappingResults;
|
||||
}
|
||||
|
||||
public Object getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
public Object getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
public List getAllResults() {
|
||||
return Collections.unmodifiableList(mappingResults);
|
||||
}
|
||||
|
||||
public boolean hasErrorResults() {
|
||||
Iterator it = mappingResults.iterator();
|
||||
while (it.hasNext()) {
|
||||
MappingResult result = (MappingResult) it.next();
|
||||
if (result.getResult().isError()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public List getErrorResults() {
|
||||
List errorResults = new ArrayList();
|
||||
Iterator it = mappingResults.iterator();
|
||||
while (it.hasNext()) {
|
||||
MappingResult result = (MappingResult) it.next();
|
||||
if (result.getResult().isError()) {
|
||||
errorResults.add(result);
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableList(errorResults);
|
||||
}
|
||||
|
||||
public List getResults(MappingResultsCriteria criteria) {
|
||||
List results = new ArrayList();
|
||||
Iterator it = mappingResults.iterator();
|
||||
while (it.hasNext()) {
|
||||
MappingResult result = (MappingResult) it.next();
|
||||
if (criteria.test(result)) {
|
||||
results.add(result);
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableList(results);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2004-2007 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.binding.mapping.impl;
|
||||
|
||||
import org.springframework.binding.convert.ConversionService;
|
||||
import org.springframework.binding.expression.EvaluationException;
|
||||
import org.springframework.binding.mapping.Mapping;
|
||||
|
||||
/**
|
||||
* A context for a mapping transaction.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface MappingContext {
|
||||
|
||||
/**
|
||||
* The object being mapped from.
|
||||
*/
|
||||
public Object getSource();
|
||||
|
||||
/**
|
||||
* The object being mapped to.
|
||||
*/
|
||||
public Object getTarget();
|
||||
|
||||
/**
|
||||
* Returns the conversion service that can be used to perform type conversions during the mapping process. May be
|
||||
* null if no externally managed conversion service is provided.
|
||||
*/
|
||||
public ConversionService getConversionService();
|
||||
|
||||
/**
|
||||
* Sets the current mapping. Called when a single mapping operation is about to begin. This updates progress of the
|
||||
* overall mapping transaction.
|
||||
* @param mapping the mapping to make the current mapping
|
||||
*/
|
||||
public void setCurrentMapping(Mapping mapping);
|
||||
|
||||
/**
|
||||
* Indicates the current mapping completed successfully.
|
||||
* @param originalValue the original value from the source of the mapping
|
||||
* @param mappedValue the successfully mapped value, which may be different from the original if a type conversion
|
||||
* was performed
|
||||
*/
|
||||
public void setSuccessResult(Object originalValue, Object mappedValue);
|
||||
|
||||
/**
|
||||
* Indicates the current mapping ended with a 'required' error. This means the value obtained from the source was
|
||||
* empty, and the mapping could not be completed as a result.
|
||||
* @param originalValue the original source value that is empty (null or an empty string, typically)
|
||||
*/
|
||||
public void setRequiredErrorResult(Object originalValue);
|
||||
|
||||
/**
|
||||
* Indicates the current mapping ended with a 'type conversion' error. This means the value obtained from the source
|
||||
* could not be converted to a type that could be assigned to the target expression.
|
||||
* @param originalValue the original source value that could not be converted during the mapping attempt
|
||||
* @param targetType the desired target type to which conversion could not be performed
|
||||
*/
|
||||
public void setTypeConversionErrorResult(Object originalValue, Class targetType);
|
||||
|
||||
/**
|
||||
* Indicates a error occurred accessing the source mapping expression.
|
||||
* @param error the error that occurred
|
||||
*/
|
||||
public void setSourceAccessError(EvaluationException error);
|
||||
|
||||
/**
|
||||
* Indicates a error occurred accessing the target mapping expression.
|
||||
* @param error the error that occurred
|
||||
*/
|
||||
public void setTargetAccessError(Object originalValue, EvaluationException error);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.springframework.binding.mapping.results;
|
||||
|
||||
import org.springframework.binding.mapping.Result;
|
||||
|
||||
public class RequiredError extends Result {
|
||||
|
||||
private Object originalValue;
|
||||
|
||||
public RequiredError(Object originalValue) {
|
||||
this.originalValue = originalValue;
|
||||
}
|
||||
|
||||
public Object getOriginalValue() {
|
||||
return originalValue;
|
||||
}
|
||||
|
||||
public Object getMappedValue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isError() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getErrorCode() {
|
||||
return "required";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.springframework.binding.mapping.results;
|
||||
|
||||
import org.springframework.binding.expression.EvaluationException;
|
||||
import org.springframework.binding.mapping.Result;
|
||||
|
||||
public class SourceAccessError extends Result {
|
||||
|
||||
private EvaluationException error;
|
||||
|
||||
public SourceAccessError(EvaluationException error) {
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public EvaluationException getException() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public Object getOriginalValue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object getMappedValue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isError() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getErrorCode() {
|
||||
return "sourceAccess";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.springframework.binding.mapping.results;
|
||||
|
||||
import org.springframework.binding.mapping.Result;
|
||||
|
||||
public class Success extends Result {
|
||||
|
||||
private Object originalValue;
|
||||
private Object mappedValue;
|
||||
|
||||
public Success(Object mappedValue, Object originalValue) {
|
||||
this.mappedValue = mappedValue;
|
||||
this.originalValue = originalValue;
|
||||
}
|
||||
|
||||
public Object getOriginalValue() {
|
||||
return originalValue;
|
||||
}
|
||||
|
||||
public Object getMappedValue() {
|
||||
return mappedValue;
|
||||
}
|
||||
|
||||
public boolean isError() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getErrorCode() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package org.springframework.binding.mapping.results;
|
||||
|
||||
import org.springframework.binding.expression.EvaluationException;
|
||||
import org.springframework.binding.expression.PropertyNotFoundException;
|
||||
import org.springframework.binding.mapping.Result;
|
||||
|
||||
public class TargetAccessError extends Result {
|
||||
|
||||
private Object originalValue;
|
||||
|
||||
private EvaluationException error;
|
||||
|
||||
public TargetAccessError(Object originalValue, EvaluationException error) {
|
||||
this.originalValue = originalValue;
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public EvaluationException getException() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public Object getOriginalValue() {
|
||||
return originalValue;
|
||||
}
|
||||
|
||||
public Object getMappedValue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isError() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getErrorCode() {
|
||||
if (error instanceof PropertyNotFoundException) {
|
||||
return "propertyNotFound";
|
||||
} else {
|
||||
return "targetAccess";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.springframework.binding.mapping.results;
|
||||
|
||||
import org.springframework.binding.mapping.Result;
|
||||
|
||||
public class TypeConversionError extends Result {
|
||||
|
||||
private Object originalValue;
|
||||
|
||||
private Class targetType;
|
||||
|
||||
public TypeConversionError(Object originalValue, Class targetType) {
|
||||
this.originalValue = originalValue;
|
||||
this.targetType = targetType;
|
||||
}
|
||||
|
||||
public Object getOriginalValue() {
|
||||
return originalValue;
|
||||
}
|
||||
|
||||
public Class getTargetType() {
|
||||
return targetType;
|
||||
}
|
||||
|
||||
public Object getMappedValue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isError() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getErrorCode() {
|
||||
return "typeMismatch";
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user