Search in sources :

Example 1 with Accessor

use of org.mapstruct.ap.internal.util.accessor.Accessor in project mapstruct by mapstruct.

the class Type method getAlternativeTargetAccessors.

/**
 * Alternative accessors could be a getter for a collection. By means of the
 * {@link java.util.Collection#addAll(java.util.Collection) } this getter can still
 * be used as targetAccessor. JAXB XJC tool generates such constructs.
 *
 * This method can be extended when new cases come along.
 *
 * @return an unmodifiable list of alternative target accessors.
 */
private List<Accessor> getAlternativeTargetAccessors() {
    if (alternativeTargetAccessors != null) {
        return alternativeTargetAccessors;
    }
    if (isRecord()) {
        alternativeTargetAccessors = Collections.emptyList();
    }
    if (alternativeTargetAccessors == null) {
        List<Accessor> result = new ArrayList<>();
        List<Accessor> setterMethods = getSetters();
        List<Accessor> readAccessors = new ArrayList<>(getPropertyReadAccessors().values());
        // All the fields are also alternative accessors
        readAccessors.addAll(filters.fieldsIn(getAllFields(), FieldElementAccessor::new));
        // (assuming it is initialized)
        for (Accessor readAccessor : readAccessors) {
            if (isCollectionOrMapOrStream(readAccessor) && !correspondingSetterMethodExists(readAccessor, setterMethods)) {
                result.add(readAccessor);
            } else if (readAccessor.getAccessorType() == AccessorType.FIELD && !correspondingSetterMethodExists(readAccessor, setterMethods)) {
                result.add(readAccessor);
            }
        }
        alternativeTargetAccessors = Collections.unmodifiableList(result);
    }
    return alternativeTargetAccessors;
}
Also used : ArrayList(java.util.ArrayList) Accessor(org.mapstruct.ap.internal.util.accessor.Accessor) PresenceCheckAccessor(org.mapstruct.ap.internal.util.accessor.PresenceCheckAccessor) FieldElementAccessor(org.mapstruct.ap.internal.util.accessor.FieldElementAccessor) ReadAccessor(org.mapstruct.ap.internal.util.accessor.ReadAccessor) MapValueAccessor(org.mapstruct.ap.internal.util.accessor.MapValueAccessor)

Example 2 with Accessor

use of org.mapstruct.ap.internal.util.accessor.Accessor in project mapstruct by mapstruct.

the class MappingMethodOptions method applyIgnoreAll.

public void applyIgnoreAll(SourceMethod method, TypeFactory typeFactory, FormattingMessager messager) {
    CollectionMappingStrategyGem cms = method.getOptions().getMapper().getCollectionMappingStrategy();
    Type writeType = method.getResultType();
    if (!method.isUpdateMethod()) {
        writeType = typeFactory.effectiveResultTypeFor(writeType, method.getOptions().getBeanMapping().getBuilder());
    }
    Map<String, Accessor> writeAccessors = writeType.getPropertyWriteAccessors(cms);
    for (MappingOptions mapping : mappings) {
        String mappedTargetProperty = getFirstTargetPropertyName(mapping);
        if (!".".equals(mappedTargetProperty)) {
            // Remove the mapped target property from the write accessors
            writeAccessors.remove(mappedTargetProperty);
        } else {
            messager.printMessage(method.getExecutable(), getBeanMapping().getMirror(), Message.BEANMAPPING_IGNORE_BY_DEFAULT_WITH_MAPPING_TARGET_THIS);
            // Nothing more to do if this is reached
            return;
        }
    }
    // The writeAccessors now contains only the accessors that should be ignored
    for (String targetPropertyName : writeAccessors.keySet()) {
        MappingOptions mapping = MappingOptions.forIgnore(targetPropertyName);
        mappings.add(mapping);
    }
}
Also used : Type(org.mapstruct.ap.internal.model.common.Type) CollectionMappingStrategyGem(org.mapstruct.ap.internal.gem.CollectionMappingStrategyGem) Accessor(org.mapstruct.ap.internal.util.accessor.Accessor)

Example 3 with Accessor

use of org.mapstruct.ap.internal.util.accessor.Accessor in project mapstruct by mapstruct.

the class Type method getAdderForType.

/**
 * Tries to find an addMethod in this type for given collection property in this type.
 *
 * Matching occurs on:
 * <ol>
 * <li>The generic type parameter type of the collection should match the adder method argument</li>
 * <li>When there are more candidates, property name is made singular (as good as is possible). This routine
 * looks for a matching add method name.</li>
 * <li>The singularization rules of Dali are used to make a property name singular. This routine
 * looks for a matching add method name.</li>
 * </ol>
 *
 * @param collectionProperty property type (assumed collection) to find  the adder method for
 * @param pluralPropertyName the property name (assumed plural)
 *
 * @return corresponding adder method for getter when present
 */
private Accessor getAdderForType(Type collectionProperty, String pluralPropertyName) {
    List<Accessor> candidates = new ArrayList<Accessor>();
    if (collectionProperty.isCollectionType) {
        // this is a collection, so this can be done always
        if (!collectionProperty.getTypeParameters().isEmpty()) {
            // there's only one type arg to a collection
            TypeMirror typeArg = collectionProperty.getTypeParameters().get(0).getTypeBound().getTypeMirror();
            // now, look for a method that
            // 1) starts with add,
            // 2) and has typeArg as one and only arg
            List<Accessor> adderList = getAdders();
            for (Accessor adder : adderList) {
                ExecutableElement executable = adder.getExecutable();
                if (executable == null) {
                    // it should not be null, but to be safe
                    continue;
                }
                VariableElement arg = executable.getParameters().get(0);
                if (typeUtils.isSameType(arg.asType(), typeArg)) {
                    candidates.add(adder);
                }
            }
        }
    }
    if (candidates.isEmpty()) {
        return null;
    } else if (candidates.size() == 1) {
        return candidates.get(0);
    } else {
        for (Accessor candidate : candidates) {
            String elementName = Executables.getElementNameForAdder(candidate);
            if (elementName != null && elementName.equals(Nouns.singularize(pluralPropertyName))) {
                return candidate;
            }
        }
    }
    return null;
}
Also used : TypeMirror(javax.lang.model.type.TypeMirror) ExecutableElement(javax.lang.model.element.ExecutableElement) ArrayList(java.util.ArrayList) VariableElement(javax.lang.model.element.VariableElement) Accessor(org.mapstruct.ap.internal.util.accessor.Accessor) ExecutableElementAccessor(org.mapstruct.ap.internal.util.accessor.ExecutableElementAccessor)

Example 4 with Accessor

use of org.mapstruct.ap.internal.util.accessor.Accessor in project mapstruct by mapstruct.

the class Executables method addNotYetOverridden.

/**
 * @param alreadyCollected methods that have already been collected and to which the not-yet-overridden methods will
 *            be added
 * @param methodsToAdd methods to add to alreadyAdded, if they are not yet overridden by an element in the list
 * @param parentType the type for with elements are collected
 */
private static void addNotYetOverridden(Elements elementUtils, List<Accessor> alreadyCollected, List<ExecutableElement> methodsToAdd, TypeElement parentType) {
    List<Accessor> safeToAdd = new ArrayList<Accessor>(methodsToAdd.size());
    for (ExecutableElement toAdd : methodsToAdd) {
        if (isNotObjectEquals(toAdd) && wasNotYetOverridden(elementUtils, alreadyCollected, toAdd, parentType)) {
            safeToAdd.add(new ExecutableElementAccessor(toAdd));
        }
    }
    alreadyCollected.addAll(0, safeToAdd);
}
Also used : ExecutableElement(javax.lang.model.element.ExecutableElement) ArrayList(java.util.ArrayList) ExecutableElementAccessor(org.mapstruct.ap.internal.util.accessor.ExecutableElementAccessor) Accessor(org.mapstruct.ap.internal.util.accessor.Accessor) VariableElementAccessor(org.mapstruct.ap.internal.util.accessor.VariableElementAccessor) ExecutableElementAccessor(org.mapstruct.ap.internal.util.accessor.ExecutableElementAccessor)

Example 5 with Accessor

use of org.mapstruct.ap.internal.util.accessor.Accessor in project mapstruct by mapstruct.

the class Type method getPropertyWriteAccessors.

/**
 * getPropertyWriteAccessors returns a map of the write accessors according to the CollectionMappingStrategy. These
 * accessors include:
 * <ul>
 * <li>setters, the obvious candidate :-), {@link #getSetters() }</li>
 * <li>readAccessors, for collections that do not have a setter, e.g. for JAXB generated collection attributes
 * {@link #getPropertyReadAccessors() }</li>
 * <li>adders, typically for from table generated entities, {@link #getAdders() }</li>
 * </ul>
 *
 * @param cmStrategy collection mapping strategy
 * @return an unmodifiable map of all write accessors indexed by property name
 */
public Map<String, Accessor> getPropertyWriteAccessors(CollectionMappingStrategyPrism cmStrategy) {
    // collect all candidate target accessors
    List<Accessor> candidates = new ArrayList<Accessor>(getSetters());
    candidates.addAll(getAlternativeTargetAccessors());
    Map<String, Accessor> result = new LinkedHashMap<String, Accessor>();
    for (Accessor candidate : candidates) {
        String targetPropertyName = Executables.getPropertyName(candidate);
        Accessor readAccessor = getPropertyReadAccessors().get(targetPropertyName);
        Type preferredType = determinePreferredType(readAccessor);
        Type targetType = determineTargetType(candidate);
        // The following if block, checks if the target accessor should be overruled by an add method.
        if (cmStrategy == CollectionMappingStrategyPrism.SETTER_PREFERRED || cmStrategy == CollectionMappingStrategyPrism.ADDER_PREFERRED || cmStrategy == CollectionMappingStrategyPrism.TARGET_IMMUTABLE) {
            // first check if there's a setter method.
            Accessor adderMethod = null;
            if (Executables.isSetterMethod(candidate) && // ok, the current accessor is a setter. So now the strategy determines what to use
            cmStrategy == CollectionMappingStrategyPrism.ADDER_PREFERRED) {
                adderMethod = getAdderForType(targetType, targetPropertyName);
            } else if (Executables.isGetterMethod(candidate)) {
                // the current accessor is a getter (no setter available). But still, an add method is according
                // to the above strategy (SETTER_PREFERRED || ADDER_PREFERRED) preferred over the getter.
                adderMethod = getAdderForType(targetType, targetPropertyName);
            }
            if (adderMethod != null) {
                // an adder has been found (according strategy) so overrule current choice.
                candidate = adderMethod;
            }
        } else if (Executables.isFieldAccessor(candidate) && (Executables.isFinal(candidate) || result.containsKey(targetPropertyName))) {
            // if the candidate is a field and a mapping already exists, then use that one, skip it.
            continue;
        }
        Accessor previousCandidate = result.get(targetPropertyName);
        if (previousCandidate == null || preferredType == null || (targetType != null && typeUtils.isAssignable(preferredType.getTypeMirror(), targetType.getTypeMirror()))) {
            result.put(targetPropertyName, candidate);
        }
    }
    return result;
}
Also used : DeclaredType(javax.lang.model.type.DeclaredType) WildcardType(javax.lang.model.type.WildcardType) ArrayList(java.util.ArrayList) Accessor(org.mapstruct.ap.internal.util.accessor.Accessor) ExecutableElementAccessor(org.mapstruct.ap.internal.util.accessor.ExecutableElementAccessor) LinkedHashMap(java.util.LinkedHashMap)

Aggregations

Accessor (org.mapstruct.ap.internal.util.accessor.Accessor)8 ArrayList (java.util.ArrayList)7 ExecutableElementAccessor (org.mapstruct.ap.internal.util.accessor.ExecutableElementAccessor)4 ExecutableElement (javax.lang.model.element.ExecutableElement)3 VariableElement (javax.lang.model.element.VariableElement)3 FieldElementAccessor (org.mapstruct.ap.internal.util.accessor.FieldElementAccessor)3 MapValueAccessor (org.mapstruct.ap.internal.util.accessor.MapValueAccessor)3 PresenceCheckAccessor (org.mapstruct.ap.internal.util.accessor.PresenceCheckAccessor)3 ReadAccessor (org.mapstruct.ap.internal.util.accessor.ReadAccessor)3 LinkedHashMap (java.util.LinkedHashMap)2 DeclaredType (javax.lang.model.type.DeclaredType)2 TypeMirror (javax.lang.model.type.TypeMirror)2 WildcardType (javax.lang.model.type.WildcardType)2 VariableElementAccessor (org.mapstruct.ap.internal.util.accessor.VariableElementAccessor)2 ArrayType (javax.lang.model.type.ArrayType)1 PrimitiveType (javax.lang.model.type.PrimitiveType)1 CollectionMappingStrategyGem (org.mapstruct.ap.internal.gem.CollectionMappingStrategyGem)1 Type (org.mapstruct.ap.internal.model.common.Type)1 AccessorType (org.mapstruct.ap.internal.util.accessor.AccessorType)1