org.nuiton.jaxx.compiler.java.JavaMethod Maven / Gradle / Ivy
The newest version!
/*
* #%L
* JAXX :: Compiler
* %%
* Copyright (C) 2008 - 2024 Code Lutin, Ultreia.io
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
package org.nuiton.jaxx.compiler.java;
import org.nuiton.jaxx.compiler.finalizers.DefaultFinalizer;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
/**
* Represents a method in a Java source file being generated for output. JavaMethods
are created
* and added to a {@link JavaFile}, which can then output Java source code. In addition to normal methods, a
* JavaMethod
can represent a constructor -- constructors should be named after their containing
* classes and have a return type of null
.
*/
public class JavaMethod extends JavaElement implements Comparable {
/**
* arguments of the method (can be empty)
*/
private final JavaArgument[] arguments;
/**
* exceptions thrown by the method (can be empty)
*/
private final String[] exceptions;
/**
* flag to known if the method override a super-method
*/
private final boolean override;
/**
* return type of the method (null for constructors)
*/
private String returnType;
/**
* body of the method (can be empty)
*/
private String body;
public static EnumMap> getSortedMethods(List methods) {
EnumMap> result =
new EnumMap<>(MethodOrder.class);
for (MethodOrder methodOrder : MethodOrder.values()) {
result.put(methodOrder, new ArrayList<>());
}
EnumSet allConstants = EnumSet.allOf(MethodOrder.class);
List allMethods = new ArrayList<>(methods);
int[] scopes = new int[]{Modifier.STATIC,
Modifier.PUBLIC,
Modifier.PROTECTED,
Modifier.PRIVATE
};
for (int scope : scopes) {
EnumSet constants =
getMethodOrderScope(allConstants, scope);
Iterator itMethods = allMethods.iterator();
while (itMethods.hasNext()) {
JavaMethod method = itMethods.next();
for (MethodOrder constant : constants) {
if (constant.accept(method.getModifiers(), method)) {
result.get(constant).add(method);
itMethods.remove();
break;
}
}
}
constants.clear();
}
if (!allMethods.isEmpty()) {
throw new IllegalArgumentException(
"could not find a " + MethodOrder.class +
" for method " + allMethods);
}
for (MethodOrder methodOrder : MethodOrder.values()) {
// sort methods
Collections.sort(result.get(methodOrder));
}
return result;
}
public static EnumSet getMethodOrderScope(EnumSet allConstants, int scope) {
EnumSet constants = EnumSet.noneOf(MethodOrder.class);
for (MethodOrder order : allConstants) {
if (order.accept(scope)) {
constants.add(order);
}
}
return constants;
}
/**
* Constructs a new JavaMethod
containing the specified body code. The modifiers
parameter
* is a bit mask of the constants from {@link Modifier}, and the returnType
and
* exceptions
of the method should be represented as they would appear in Java source code (null
* for a constructor). The method body is initially empty.
*
* @param modifiers the modifier keywords that should appear as part of the method's declaration
* @param returnType the return type of the method as it would appear in Java source code
* @param name the method's name
* @param arguments the method's arguments
* @param exceptions a list of exceptions the methods can throw, as they would be represented in Java source code
* @param bodyCode Java source code which should appear in the method body
* @param override flag with {@code true} value when the method overrides (or implements) a super class method
*/
JavaMethod(int modifiers,
String returnType,
String name,
JavaArgument[] arguments,
String[] exceptions,
String bodyCode,
boolean override) {
super(modifiers, name);
this.returnType = returnType;
this.override = override;
this.arguments = arguments;
this.exceptions = exceptions;
body = bodyCode == null ? "" : bodyCode;
}
/**
* Returns the method's return type, as it would be represented
* in Java source code.
*
* @return the method's return type
*/
public String getReturnType() {
return returnType;
}
/**
* Returns a list of the method's arguments.
*
* @return the method's arguments
*/
public JavaArgument[] getArguments() {
return arguments;
}
/**
* Returns a list of exceptions the method can throw.
*
* @return the method's exceptions
*/
public String[] getExceptions() {
return exceptions;
}
public boolean isOverride() {
return override;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
@Override
public int compareTo(JavaMethod o) {
return JavaElementComparator.compare(this, o);
}
public void setReturnType(String returnType) {
this.returnType = returnType;
}
public enum MethodOrder {
statics(Modifier.STATIC, "Statics methods"),
constructors(Modifier.PUBLIC, "Constructors") {
@Override
public boolean accept(JavaMethod method) {
return method.returnType == null;
}
},
JAXXObject(Modifier.PUBLIC, "JAXXObject implementation") {
private final List methods = List.of(
DefaultFinalizer.METHOD_NAME_APPLY_DATA_BINDING,
DefaultFinalizer.METHOD_NAME_FIRE_PROPERTY_CHANGE,
DefaultFinalizer.METHOD_NAME_PROCESS_DATA_BINDING,
DefaultFinalizer.METHOD_NAME_REMOVE_DATA_BINDING,
DefaultFinalizer.METHOD_NAME_REGISTER_DATA_BINDING,
"getObjectById",
"get$objectMap",
"getDataBindings",
"getDataBinding");
@Override
public boolean accept(JavaMethod method) {
return methods.contains(method.getName());
}
},
JAXXContext(Modifier.PUBLIC, "JAXXContext implementation") {
private final List methods = List.of(
"getContextValue",
"getDelegateContext",
"getParentContainer",
"removeContextValue",
"setContextValue");
@Override
public boolean accept(JavaMethod method) {
return methods.contains(method.getName());
}
},
JAXXValidation(Modifier.PUBLIC, "JAXXValidator implementation") {
private final List methods =
List.of("createValidatorEditors", "getValidator", "getValidatorEditors", "getValidatorIds", "registerValidatorFields");
@Override
public boolean accept(JavaMethod method) {
boolean contains = methods.contains(method.getName());
if (contains && method.getName().equals("getValidator")) {
// only accept the method getValidator(String) and not anything else...
// since user can have a validator field which is a validator, but not part of the
// JAXXValidator contract
return method.getArguments().length == 1;
}
return contains;
}
},
events(Modifier.PUBLIC, "Event methods") {
@Override
public boolean accept(JavaMethod method) {
return method.getName().startsWith("do") &&
method.getName().contains("__");
}
},
publicGetters(Modifier.PUBLIC, "Public accessor methods") {
@Override
public boolean accept(JavaMethod method) {
return method.getName().startsWith("get") ||
method.getName().startsWith("is");
}
},
publicSetters(Modifier.PUBLIC, "Public mutator methods") {
@Override
public boolean accept(JavaMethod method) {
return method.getName().startsWith("set");
}
},
otherPublic(Modifier.PUBLIC, "Other methods") {
@Override
public boolean accept(int mod) {
return super.accept(mod) && !Modifier.isStatic(mod);
}
},
protectedGetters(Modifier.PROTECTED, "Protected accessors methods") {
@Override
public boolean accept(JavaMethod method) {
return method.getName().startsWith("get") ||
method.getName().startsWith("is");
}
},
createMethod(Modifier.PROTECTED | Modifier.PRIVATE,
"Components creation methods") {
@Override
public boolean accept(JavaMethod method) {
return method.getName().startsWith("create") ||
method.getName().startsWith("add");
}
},
internalMethod(Modifier.PROTECTED, "Internal jaxx methods") {
private final List methods = List.of(
DefaultFinalizer.METHOD_NAME_$INITIALIZE,
DefaultFinalizer.METHOD_NAME_$INITIALIZE_01_CREATE_HANDLER,
DefaultFinalizer.METHOD_NAME_$INITIALIZE_01_CREATE_COMPONENTS,
DefaultFinalizer.METHOD_NAME_$INITIALIZE_02_REGISTER_DATA_BINDINGS,
DefaultFinalizer.METHOD_NAME_$INITIALIZE_03_FINALIZE_CREATE_COMPONENTS,
DefaultFinalizer.METHOD_NAME_$INITIALIZE_03_REGISTER_ACTIONS,
DefaultFinalizer.METHOD_NAME_$INITIALIZE_04_APPLY_DATA_BINDINGS,
DefaultFinalizer.METHOD_NAME_$INITIALIZE_05_SET_PROPERTIES,
DefaultFinalizer.METHOD_NAME_$INITIALIZE_06_FINALIZE_INITIALIZE);
@Override
public boolean accept(JavaMethod method) {
return methods.contains(method.getName());
}
},
protecteds(Modifier.PROTECTED, "Other protected methods") {
},
packageLocal(0, "Package methods") {
@Override
public boolean accept(int mod) {
return !Modifier.isStatic(mod) &&
!Modifier.isPublic(mod) &&
!Modifier.isProtected(mod);
}
},
privates(Modifier.PRIVATE, "Other private methods");
private final String header;
private final int modifier;
public static MethodOrder valueOf(JavaMethod method, int scope) {
for (MethodOrder o : values()) {
if (o.accept(scope, method)) {
return o;
}
}
throw new IllegalArgumentException(
"could not find a " + MethodOrder.class +
" for method " + method);
}
MethodOrder(int modifier, String header) {
this.header = JavaFileGenerator.getHeader(header);
this.modifier = modifier;
}
public String getHeader() {
return header;
}
public boolean accept(JavaMethod method) {
return true;
}
public boolean accept(int mod) {
return (mod & modifier) != 0;
}
public boolean accept(int mod, JavaMethod method) {
return accept(mod) && accept(method);
}
}
}