@SuppressWarnings("unchecked") private <S, D> void propertyMap(Mapping mapping, MappingContextImpl<S, D> context) { MappingImpl mappingImpl = (MappingImpl) mapping; if (context.isShaded(mappingImpl.getPath())) return; Condition<Object, Object> condition = (Condition<Object, Object>) mapping.getCondition(); if (condition == null) condition = (Condition<Object, Object>) context.getTypeMap().getPropertyCondition(); if (condition == null && mapping.isSkipped()) return; Object source = resolveSourceValue(context, mapping); MappingContextImpl<Object, Object> propertyContext = propertyContextFor(context, source, mapping); if (condition != null) { if (!condition.applies(propertyContext)) { context.shadePath(mappingImpl.getPath()); return; } else if (mapping.isSkipped()) return; } Converter<Object, Object> converter = (Converter<Object, Object>) mapping.getConverter(); if (converter == null) converter = (Converter<Object, Object>) context.getTypeMap().getPropertyConverter(); if (converter != null) context.shadePath(mappingImpl.getPath()); else if (mapping instanceof SourceMapping) return; // Create destination for property context prior to mapping/conversion createDestinationViaProvider(propertyContext); // Set mapped/converted destination value setDestinationValue(context, propertyContext, mappingImpl, converter); }
/** * Performs mapping using a TypeMap if one exists, else a converter if one applies, else a newly * created TypeMap. Recursive entry point. */ public <S, D> D map(MappingContext<S, D> context) { MappingContextImpl<S, D> contextImpl = (MappingContextImpl<S, D>) context; Class<D> destinationType = context.getDestinationType(); // Resolve some circular dependencies if (!Iterables.isIterable(destinationType)) { D circularDest = contextImpl.destinationForSource(); if (circularDest != null) return circularDest; } D destination = null; TypeMap<S, D> typeMap = typeMapStore.get(context.getSourceType(), context.getDestinationType()); if (typeMap != null) { destination = typeMap(contextImpl, typeMap); } else { Converter<S, D> converter = converterFor(context); if (converter != null) { destination = convert(context, converter); } else { // Call getOrCreate in case TypeMap was created concurrently typeMap = typeMapStore.getOrCreate(context.getSourceType(), context.getDestinationType(), this); destination = typeMap(contextImpl, typeMap); } } return destination; }
public <S, D> D createDestination(MappingContext<S, D> context) { MappingContextImpl<S, D> contextImpl = (MappingContextImpl<S, D>) context; D destination = createDestinationViaProvider(contextImpl); if (destination != null) return destination; destination = instantiate(context.getDestinationType(), contextImpl.errors); contextImpl.setDestination(destination); return destination; }
@SuppressWarnings("unchecked") private Object resolveSourceValue(MappingContextImpl<?, ?> context, Mapping mapping) { Object source = context.getSource(); if (mapping instanceof PropertyMappingImpl) { for (Accessor accessor : (List<Accessor>) ((PropertyMapping) mapping).getSourceProperties()) { context.setParentSource(source); source = accessor.getValue(source); if (source == null) return null; if (!Iterables.isIterable(source.getClass())) { Object circularDest = context.sourceToDestination.get(source); if (circularDest != null) context.intermediateDestinations.add(circularDest); } } } else if (mapping instanceof ConstantMapping) source = ((ConstantMapping) mapping).getConstant(); return source; }
/** Performs a type mapping for the {@code typeMap} and {@code context}. */ <S, D> D typeMap(MappingContextImpl<S, D> context, TypeMap<S, D> typeMap) { context.setTypeMap(typeMap); if (context.getDestination() == null && Types.isInstantiable(context.getDestinationType())) { D destination = createDestination(context); if (destination == null) return null; } @SuppressWarnings("unchecked") Condition<S, D> condition = (Condition<S, D>) typeMap.getCondition(); Converter<S, D> converter = typeMap.getConverter(); if (condition == null || condition.applies(context)) { if (converter != null) return convert(context, converter); converter = typeMap.getPreConverter(); if (converter != null) convert(context, converter); for (Mapping mapping : typeMap.getMappings()) propertyMap(mapping, context); converter = typeMap.getPostConverter(); if (converter != null) convert(context, converter); } return context.getDestination(); }
/** * Returns a destination object via a provider with the current Mapping's provider used first, * else the TypeMap's property provider, else the TypeMap's provider, else the configuration's * provider. */ @SuppressWarnings("unchecked") private <S, D> D createDestinationViaProvider(MappingContextImpl<S, D> context) { Provider<D> provider = null; if (context.getMapping() != null) { provider = (Provider<D>) context.getMapping().getProvider(); if (provider == null && context.parentTypeMap() != null) provider = (Provider<D>) context.parentTypeMap().getPropertyProvider(); } if (provider == null && context.getTypeMap() != null) provider = context.getTypeMap().getProvider(); if (provider == null && configuration.getProvider() != null) provider = (Provider<D>) configuration.getProvider(); if (provider == null) return null; D destination = provider.get(context); if (destination != null && !context.getDestinationType().isAssignableFrom(destination.getClass())) context.errors.invalidProvidedDestinationInstance(destination, context.getDestinationType()); context.setDestination(destination); return destination; }
/** * Sets a mapped or converted destination value in the last mapped mutator for the given {@code * mapping}. The final destination value is resolved by walking the {@code mapping}'s mutator * chain and obtaining each destination value in the chain either from the cache, from a * corresponding accessor, from a provider, or by instantiation, in that order. */ @SuppressWarnings({"unchecked", "rawtypes"}) private void setDestinationValue( MappingContextImpl<?, ?> context, MappingContextImpl<Object, Object> propertyContext, MappingImpl mapping, Converter<Object, Object> converter) { Object destination = context.getDestination(); List<Mutator> mutatorChain = (List<Mutator>) mapping.getDestinationProperties(); StringBuilder destPathBuilder = new StringBuilder(); for (int i = 0; i < mutatorChain.size(); i++) { Mutator mutator = mutatorChain.get(i); destPathBuilder.append(mutator.getName()).append('.'); String destPath = destPathBuilder.toString(); // Handle last mutator in chain if (i == mutatorChain.size() - 1) { // Final destination value Object destinationValue = null; if (converter != null) { // Obtain from accessor on provided destination if (context.providedDestination) { Accessor accessor = TypeInfoRegistry.typeInfoFor(destination.getClass(), configuration) .getAccessors() .get(mutator.getName()); if (accessor != null) { Object intermediateDest = accessor.getValue(destination); propertyContext.setDestination(intermediateDest); } } destinationValue = convert(propertyContext, converter); } else if (propertyContext.getSource() != null) destinationValue = map(propertyContext); context.destinationCache.put(destPath, destinationValue); mutator.setValue( destination, destinationValue == null ? Primitives.defaultValue(mutator.getType()) : destinationValue); if (destinationValue == null) context.shadePath(mapping.getPath()); } else { // Obtain from cache Object intermediateDest = context.destinationCache.get(destPath); if (intermediateDest != null) { mutator.setValue(destination, intermediateDest); } else { // Obtain from circular destinations if (!context.intermediateDestinations.isEmpty()) { for (Object intermediateDestination : context.intermediateDestinations) { // Match intermediate destinations to mutator by type if (intermediateDestination.getClass().equals(mutator.getType())) { intermediateDest = intermediateDestination; mutator.setValue(destination, intermediateDest); break; } } } if (intermediateDest == null) { // Obtain from accessor on provided destination if (context.providedDestination) { Accessor accessor = TypeInfoRegistry.typeInfoFor(destination.getClass(), configuration) .getAccessors() .get(mutator.getName()); if (accessor != null) intermediateDest = accessor.getValue(destination); } // Obtain from new instance if (intermediateDest == null) { if (propertyContext.getSource() == null) return; Provider<?> globalProvider = configuration.getProvider(); if (globalProvider != null) intermediateDest = globalProvider.get( new ProvisionRequestImpl(context.parentSource(), mutator.getType())); else intermediateDest = instantiate(mutator.getType(), context.errors); if (intermediateDest == null) return; mutator.setValue(destination, intermediateDest); } } context.destinationCache.put(destPath, intermediateDest); } destination = intermediateDest; } } }