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;
}
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);
}
}
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;
}
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);
}
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;
}
Aggregations