lombok.core.handlers.InclusionExclusionUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of lombok Show documentation
Show all versions of lombok Show documentation
Spice up your java: Automatic Resource Management, automatic generation of getters, setters, equals, hashCode and toString, and more!
The newest version!
/*
* Copyright (C) 2009-2020 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package lombok.core.handlers;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.core.AST;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
import lombok.core.LombokNode;
public class InclusionExclusionUtils {
private static List createListOfNonExistentFields(List list, LombokNode, ?, ?> type, boolean excludeStandard, boolean excludeTransient) {
boolean[] matched = new boolean[list.size()];
for (LombokNode, ?, ?> child : type.down()) {
if (list.isEmpty()) break;
if (child.getKind() != Kind.FIELD) continue;
if (excludeStandard) {
if (child.isStatic()) continue;
if (child.getName().startsWith("$")) continue;
}
if (excludeTransient && child.isTransient()) continue;
int idx = list.indexOf(child.getName());
if (idx > -1) matched[idx] = true;
}
List problematic = new ArrayList();
for (int i = 0 ; i < list.size() ; i++) if (!matched[i]) problematic.add(i);
return problematic;
}
public static void checkForBogusFieldNames(LombokNode, ?, ?> type, AnnotationValues> annotation, List excludes, List includes) {
if (excludes != null && !excludes.isEmpty()) {
for (int i : createListOfNonExistentFields(excludes, type, true, false)) {
if (annotation != null) annotation.setWarning("exclude", "This field does not exist, or would have been excluded anyway.", i);
}
}
if (includes != null && !includes.isEmpty()) {
for (int i : createListOfNonExistentFields(includes, type, false, false)) {
if (annotation != null) annotation.setWarning("of", "This field does not exist.", i);
}
}
}
public static class Included {
private final L node;
private final I inc;
private final boolean defaultInclude;
private final boolean explicitRank;
public Included(L node, I inc, boolean defaultInclude, boolean explicitRank) {
this.node = node;
this.inc = inc;
this.defaultInclude = defaultInclude;
this.explicitRank = explicitRank;
}
public L getNode() {
return node;
}
public I getInc() {
return inc;
}
public boolean isDefaultInclude() {
return defaultInclude;
}
public boolean hasExplicitRank() {
return explicitRank;
}
}
private static String innerAnnName(Class extends Annotation> type) {
String name = type.getSimpleName();
Class> c = type.getEnclosingClass();
while (c != null) {
name = c.getSimpleName() + "." + name;
c = c.getEnclosingClass();
}
return name;
}
private static , L extends LombokNode, N, I extends Annotation> List> handleIncludeExcludeMarking(Class inclType, String replaceName, Class extends Annotation> exclType, LombokNode typeNode, AnnotationValues> annotation, LombokNode annotationNode, boolean includeTransient) {
boolean onlyExplicitlyIncluded = annotation != null ? annotation.getAsBoolean("onlyExplicitlyIncluded") : false;
return handleIncludeExcludeMarking(inclType, onlyExplicitlyIncluded, replaceName, exclType, typeNode, annotation, annotationNode, includeTransient);
}
private static , L extends LombokNode, N, I extends Annotation> List> handleIncludeExcludeMarking(Class inclType, boolean onlyExplicitlyIncluded, String replaceName, Class extends Annotation> exclType, LombokNode typeNode, AnnotationValues> annotation, LombokNode annotationNode, boolean includeTransient) {
List oldExcludes = (annotation != null && annotation.isExplicit("exclude")) ? annotation.getAsStringList("exclude") : null;
List oldIncludes = (annotation != null && annotation.isExplicit("of")) ? annotation.getAsStringList("of") : null;
boolean memberAnnotationMode = onlyExplicitlyIncluded;
List> members = new ArrayList>();
List namesToAutoExclude = new ArrayList();
if (typeNode == null || typeNode.getKind() != Kind.TYPE) return null;
checkForBogusFieldNames(typeNode, annotation, oldExcludes, oldIncludes);
if (oldExcludes != null && oldIncludes != null) {
oldExcludes = null;
if (annotation != null) annotation.setWarning("exclude", "exclude and of are mutually exclusive; the 'exclude' parameter will be ignored.");
}
for (L child : typeNode.down()) {
boolean markExclude = child.getKind() == Kind.FIELD && child.hasAnnotation(exclType);
AnnotationValues markInclude = null;
if (child.getKind() == Kind.FIELD || child.getKind() == Kind.METHOD) markInclude = child.findAnnotation(inclType);
if (markExclude || markInclude != null) memberAnnotationMode = true;
if (markInclude != null && markExclude) {
child.addError("@" + innerAnnName(exclType) + " and @" + innerAnnName(inclType) + " are mutually exclusive; the @Include annotation will be ignored");
markInclude = null;
}
String name = child.getName();
if (markExclude) {
if (onlyExplicitlyIncluded) {
child.addWarning("The @Exclude annotation is not needed; 'onlyExplicitlyIncluded' is set, so this member would be excluded anyway");
} else if (child.isStatic()) {
child.addWarning("The @Exclude annotation is not needed; static fields aren't included anyway");
} else if (name.startsWith("$")) {
child.addWarning("The @Exclude annotation is not needed; fields that start with $ aren't included anyway");
}
continue;
}
if (oldExcludes != null && oldExcludes.contains(name)) continue;
if (markInclude != null) {
I inc = markInclude.getInstance();
if (child.getKind() == Kind.METHOD) {
if (child.countMethodParameters() > 0) {
child.addError("Methods included with @" + innerAnnName(inclType) + " must have no arguments; it will not be included");
continue;
}
String n = replaceName != null ? markInclude.getAsString(replaceName) : "";
if (n.isEmpty()) n = name;
namesToAutoExclude.add(n);
}
members.add(new Included(child, inc, false, markInclude.isExplicit("rank")));
continue;
}
if (onlyExplicitlyIncluded) continue;
if (oldIncludes != null) {
if (child.getKind() == Kind.FIELD && oldIncludes.contains(name)) members.add(new Included(child, null, false, false));
continue;
}
if (child.getKind() != Kind.FIELD) continue;
if (child.isStatic()) continue;
if (child.isTransient() && !includeTransient) continue;
if (name.startsWith("$")) continue;
if (child.isEnumMember()) continue;
members.add(new Included(child, null, true, false));
}
/* delete default-included fields with the same name as an explicit inclusion */ {
Iterator> it = members.iterator();
while (it.hasNext()) {
Included m = it.next();
if (m.isDefaultInclude() && namesToAutoExclude.contains(m.getNode().getName())) it.remove();
}
}
if (annotation == null || !annotation.isExplicit("exclude")) oldExcludes = null;
if (annotation == null || !annotation.isExplicit("of")) oldIncludes = null;
if (memberAnnotationMode && (oldExcludes != null || oldIncludes != null)) {
annotationNode.addError("The old-style 'exclude/of' parameter cannot be used together with the new-style @Include / @Exclude annotations.");
return null;
}
return members;
}
public static , L extends LombokNode, N> List> handleToStringMarking(LombokNode typeNode, boolean onlyExplicitlyIncluded, AnnotationValues annotation, LombokNode annotationNode) {
List> members = handleIncludeExcludeMarking(ToString.Include.class, onlyExplicitlyIncluded, "name", ToString.Exclude.class, typeNode, annotation, annotationNode, true);
Collections.sort(members, new Comparator>() {
@Override public int compare(Included a, Included b) {
int ra = a.getInc() == null ? 0 : a.getInc().rank();
int rb = b.getInc() == null ? 0 : b.getInc().rank();
return compareRankOrPosition(ra, rb, a.getNode(), b.getNode());
}
});
return members;
}
public static , L extends LombokNode, N> List> handleEqualsAndHashCodeMarking(LombokNode typeNode, AnnotationValues annotation, LombokNode annotationNode) {
List> members = handleIncludeExcludeMarking(EqualsAndHashCode.Include.class, "replaces", EqualsAndHashCode.Exclude.class, typeNode, annotation, annotationNode, false);
Collections.sort(members, new Comparator>() {
@Override public int compare(Included a, Included b) {
int ra = a.hasExplicitRank() ? a.getInc().rank() : HandlerUtil.defaultEqualsAndHashcodeIncludeRank(a.node.fieldOrMethodBaseType());
int rb = b.hasExplicitRank() ? b.getInc().rank() : HandlerUtil.defaultEqualsAndHashcodeIncludeRank(b.node.fieldOrMethodBaseType());
return compareRankOrPosition(ra, rb, a.getNode(), b.getNode());
}
});
return members;
}
private static , L extends LombokNode, N> int compareRankOrPosition(int ra, int rb, LombokNode nodeA, LombokNode nodeB) {
if (ra < rb) return +1;
if (ra > rb) return -1;
int pa = nodeA.getStartPos();
int pb = nodeB.getStartPos();
if (pa < pb) return -1;
if (pa > pb) return +1;
return 0;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy