![JAR search and dependency download from the Maven repository](/logo.png)
net.projectmonkey.internal.MappingBuilderImpl Maven / Gradle / Ivy
/*
* Copyright 2011 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 net.projectmonkey.internal;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import net.projectmonkey.Condition;
import net.projectmonkey.ConfigurationException;
import net.projectmonkey.Converter;
import net.projectmonkey.PropertyMap;
import net.projectmonkey.Provider;
import net.projectmonkey.builder.ConditionExpression;
import net.projectmonkey.config.Configuration;
import net.projectmonkey.internal.MappingProgress.DestinationProgress;
import net.projectmonkey.internal.MappingProgress.SourceProgress;
import net.projectmonkey.internal.util.Assert;
import net.projectmonkey.internal.util.Types;
/**
* Builds explicit property mappings.
*
* @author Jonathan Halterman
*/
public class MappingBuilderImpl implements ConditionExpression {
private static Method PROPERTY_MAP_CONFIGURE;
private final Class sourceType;
private final Class destinationType;
final Configuration configuration;
volatile S source;
private volatile D destination;
final Errors errors = new Errors();
private final Set propertyMappings = new HashSet();
private final SourceProgress sourceProgress;
private final DestinationProgress destinationProgress;
private MappingOptions options = new MappingOptions();
boolean destinationRequested;
static {
PROPERTY_MAP_CONFIGURE = Types.methodFor(PropertyMap.class, "configure",
MappingBuilderImpl.class);
PROPERTY_MAP_CONFIGURE.setAccessible(true);
}
static class MappingOptions {
Condition, ?> condition;
Converter, ?> converter;
Provider> provider;
boolean skip;
boolean mapFromSource;
}
MappingBuilderImpl(Class sourceType, Class destinationType, Configuration configuration) {
this.sourceType = sourceType;
this.destinationType = destinationType;
this.configuration = configuration;
sourceProgress = new SourceProgress(this);
destinationProgress = new DestinationProgress(this);
}
public D skip() {
saveLastMapping();
options.skip = true;
return getDestination();
}
public D map() {
saveLastMapping();
return getDestination();
}
public D map(Object source) {
saveLastMapping();
options.mapFromSource = source == this.source;
return getDestination();
}
public ConditionExpression using(Converter, ?> converter) {
saveLastMapping();
Assert.state(options.converter == null, "using() can only be called once per mapping.");
options.converter = converter;
return this;
}
public ConditionExpression when(Condition, ?> condition) {
saveLastMapping();
Assert.state(options.condition == null, "when() can only be called once per mapping.");
options.condition = condition;
return this;
}
public ConditionExpression withProvider(Provider> provider) {
saveLastMapping();
Assert.state(options.provider == null, "withProvider() can only be called once per mapping.");
options.provider = provider;
return this;
}
/**
* Builds and returns all property mappings defined in the {@code propertyMap}.
*
* @return map of destination property names to mappings
*/
Collection build(PropertyMap propertyMap) {
try {
PROPERTY_MAP_CONFIGURE.invoke(propertyMap, this);
saveLastMapping();
} catch (IllegalAccessException e) {
errors.errorAccessingConfigure(e);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
if (cause instanceof NullPointerException) {
errors.invocationAgainstFinalClassOrMethod();
} else if (cause instanceof ConfigurationException)
errors.merge(((ConfigurationException) cause).getErrorMessages());
else
errors.addError("building mappings", cause);
}
errors.throwConfigurationExceptionIfErrorsExist();
return propertyMappings;
}
private D getDestination() {
destinationRequested = true;
if (destination == null) {
synchronized (MappingBuilderImpl.class) {
if (destination == null) {
try {
destination = ProxyFactory.proxyFor(destinationType, destinationProgress);
} catch (ErrorsException e) {
errors.merge(e.getErrors());
errors.throwConfigurationExceptionIfErrorsExist();
}
}
}
}
return destination;
}
public S getSource() {
if (source == null) {
synchronized (MappingBuilderImpl.class) {
if (source == null) {
try {
source = ProxyFactory.proxyFor(sourceType, sourceProgress);
} catch (ErrorsException e) {
errors.merge(e.getErrors());
errors.throwConfigurationExceptionIfErrorsExist();
}
}
}
}
return source;
}
private void saveLastMapping() {
if (!destinationRequested) {
// if (sourceProgress.hasProperties())
// errors.sourceOutsideOfMap();
return;
}
if (destinationProgress.propertyInfo.isEmpty())
errors.missingDestination();
// if (options.mapFromSource && options.converter == null)
// errors.mapFromSourceWithoutConverter();
try {
if (!destinationProgress.propertyInfo.isEmpty()) {
MappingImpl mapping = null;
if (options.mapFromSource)
mapping = new SourceMappingImpl(sourceType, destinationProgress.propertyInfo, options);
else if (sourceProgress.propertyInfo.isEmpty())
mapping = new ConstantMappingImpl(destinationProgress.argument,
destinationProgress.propertyInfo, options);
else
mapping = new PropertyMappingImpl(sourceProgress.propertyInfo,
destinationProgress.propertyInfo, options);
if (!propertyMappings.add(mapping))
errors.duplicateMapping(mapping.getLastDestinationProperty());
}
} finally {
sourceProgress.reset();
destinationProgress.reset();
options = new MappingOptions();
destinationRequested = false;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy