io.github.mletkin.numerobis.generator.common.ClassUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of builder-generator-maven-plugin Show documentation
Show all versions of builder-generator-maven-plugin Show documentation
Maven plugin that generates builder classes for existing classes
The newest version!
/**
* (c) 2019 by Ullrich Rieger
*
* 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 io.github.mletkin.numerobis.generator.common;
import static io.github.mletkin.numerobis.common.Util.exists;
import java.util.Collection;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Stream;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.ImportDeclaration;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.body.CallableDeclaration;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.ConstructorDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.expr.SimpleName;
import com.github.javaparser.ast.type.Type;
import io.github.mletkin.numerobis.annotation.Ignore;
/**
* Convenience Methods for class declarations.
*/
public final class ClassUtil {
private ClassUtil() {
// prevent instantiation
}
/**
* Checks a compilation unit for a given class.
*
* @param unit
* compilation unit to check
* @param className
* name of the searched class
* @return the found class declaration wrapped in an optional
*/
public static Optional findClass(CompilationUnit unit, String className) {
return unit.findFirst(ClassOrInterfaceDeclaration.class, //
cl -> cl.getNameAsString().equals(className));
}
/**
* Checks a class declaration for a constructor.
*
* @param type
* class to check
* @return {@code true} if the class contains a constructor
*/
public static boolean hasExplicitConstructor(ClassOrInterfaceDeclaration type) {
return exists(allMember(type, ConstructorDeclaration.class));
}
/**
* Checks a class declaration for a default constructor.
*
* @param type
* class to check
* @return {@code true} if the class contains a default constructor.
*/
public static boolean hasDefaultConstructor(ClassOrInterfaceDeclaration type) {
return exists(allMember(type, ConstructorDeclaration.class) //
.filter(cd -> cd.getParameters().isEmpty()));
}
/**
* Checks a class declaration for a product constructor.
*
* @param type
* class to check
* @param productClassName
* name of the product class
* @return {@code true} if the class contains a product constructor.
*/
public static boolean hasProductConstructor(ClassOrInterfaceDeclaration type, String productClassName) {
return allMember(type, ConstructorDeclaration.class) //
.filter(cd -> cd.getParameters().size() == 1) //
.anyMatch(cd -> cd.getParameter(0).getTypeAsString().equals(productClassName));
}
/**
* Checks a constructor declaration for builder usage.
*
* @param cd
* constructor declartion to check
* @return {@code true} if the builder should have a corresponding constructor
*/
public static boolean process(ConstructorDeclaration cd) {
return !cd.isPrivate() && !cd.isAnnotationPresent(Ignore.class);
}
/**
* Checks, whether a variable type is a {@code Collection}.
*
* @param vd
* declaration of the variable to check
* @param cu
* Compilation unit with imports
* @return {@code true}, if the type is a {@code Collection}
*/
public static boolean isCollection(VariableDeclarator vd, CompilationUnit cu) {
return extendsInterface(vd.getType(), Collection.class, cu);
}
/**
* Checks, whether a field declaration type is a {@code Collection}.
*
* @param fd
* field declaration to check
* @param cu
* Compilation unit with imports
* @return {@code true}, if the type is a {@code Collection}
*/
public static boolean isCollection(FieldDeclaration fd, CompilationUnit cu) {
return extendsInterface(fd.getElementType(), Collection.class, cu);
}
/**
* Checks, whether a type extends a given interface.
*
* @param type
* Type to check
* @param clazz
* Class object of the interface
* @param cu
* Compilation unit with imports
* @return {@code true}, if the type extends the interface
*/
public static boolean extendsInterface(Type type, Class> clazz, CompilationUnit cu) {
String typ = type.findFirst(SimpleName.class).map(SimpleName::asString).orElse("#");
Optional fullType = cu.getImports().stream() //
.map(ImportDeclaration::getNameAsString) //
.filter(i -> i.endsWith(typ)) //
.findFirst();
try {
if (fullType.isPresent()) {
Class> c = Class.forName(fullType.get());
c.asSubclass(clazz);
return true;
}
} catch (ClassCastException | ClassNotFoundException e) {
return false;
}
return false;
}
/**
* Compares the parameter types of two method or constructor declarations.
*
* @param a
* first declaration to compare
* @param b
* second declaration to compare
* @return {@code true} if both type lists are identical
*/
public static boolean matchesParameter(CallableDeclaration> a, CallableDeclaration> b) {
if (a.getParameters().size() != b.getParameters().size()) {
return false;
}
for (int n = 0; n < a.getParameters().size(); n++) {
if (!a.getParameter(n).getTypeAsString().equals(b.getParameter(n).getTypeAsString())) {
return false;
}
}
return true;
}
/**
* Returns all members of a given type for a class declaration.
*
* @param
* member Type
* @param decl
* class declaration
* @param memberType
* class object of the member type
* @return stream of members
*/
public static Stream allMember(ClassOrInterfaceDeclaration decl, Class memberType) {
return decl.findAll(memberType) //
.stream() //
.filter(isMember(decl));
}
private static Predicate isMember(Node parent) {
return node -> node.getParentNode().orElse(null) == parent;
}
/**
* Produces a predicate to check that a method has exactly one parameter.
*
* @param type
* the type, the parameter must have
* @return the predicate
*/
public static Predicate> hasSingleParameter(Type type) {
return md -> md.getParameters().size() == 1 && md.getParameter(0).getType().equals(type);
}
/**
* Produces a predicate to check that a method has exactly one vararg parameter.
*
* @param type
* the type, the parameter must have
* @return the predicate
*/
public static Predicate> hasSingleVarArgParameter(Type type) {
return md -> md.getParameters().size() == 1 //
&& md.getParameter(0).getType().equals(type) //
&& md.getParameter(0).isVarArgs();
}
/**
* Returns the type of the first type parameter.
*
* @param type
* type with parameters
* @return type of the first type parameter
*/
public static Type firstTypeArgument(Type type) {
return type.asClassOrInterfaceType().getTypeArguments().get().get(0);
}
}