org.nuiton.jaxx.compiler.java.JavaField 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 java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
/**
* Represents a field in a Java source file being generated for output. JavaFields
are created
* and added to a {@link JavaFile}, which can then output Java source code.
*/
public class JavaField extends JavaElement implements Comparable {
/** type of field (fqn) */
private String type;
/** initializer of field (can be null) */
private String initializer;
/**
* Types to apply to the initializer to try use simple type names.
*
* @since 2.4
*/
private final String[] initializerTypes;
/** flag to known where a field overrides a super-field */
private final boolean override;
/**
* Constructs a new JavaField
. The modifiers
parameter is a bit mask of the
* constants from {@link Modifier}, and the type
of the field should be
* represented as it would appear in Java source code.
*
* @param modifiers the modifier keywords that should appear as part of the field's declaration
* @param type the type of the field as it would appear in Java source code
* @param name the field's name
* @param override flag to add @Override annotation on getter and setter
*/
JavaField(int modifiers,
String type,
String name,
boolean override) {
this(modifiers, type, name, override, null);
}
/**
* Constructs a new JavaField
. The modifiers
parameter is a bit mask of the
* constants from java.lang.reflect.Modifier
, and the type
of the field should be
* represented as it would appear in Java source code. The initializer
is the initial
* value of the field as it would appear in Java source code, or null
to leave it at the
* default value.
*
* @param modifiers the modifier keywords that should appear as part of the field's declaration
* @param type the type of the field as it would appear in Java source code
* @param name the field's name
* @param override {@code true} if method should be marked as overriden
* @param initializer the initial value of the field, as it would appear in Java source code
* @param initializerTypes initializer types to use
*/
JavaField(int modifiers,
String type,
String name,
boolean override,
String initializer,
String... initializerTypes) {
super(modifiers, name);
this.type = type;
this.initializer = initializer;
this.initializerTypes = initializerTypes;
this.override = override;
}
/**
* Returns the field's type, as it would be represented in Java source code.
*
* @return the field's type
*/
public String getType() {
return type;
}
public boolean isOverride() {
return override;
}
public String getInitializer() {
return initializer;
}
public String[] getInitializerTypes() {
return initializerTypes;
}
public boolean hasInitializerTypes() {
return initializerTypes != null && initializerTypes.length > 0;
}
@Override
public int compareTo(JavaField o) {
return JavaElementComparator.compare(this, o);
}
@Override
public String toString() {
return super.toString() + " " + getName() + ", type:" +
getType() + ", modifiers:" + Modifier.toString(getModifiers());
}
public void setType(String type) {
this.type = type;
}
public void setInitializer(String initializer) {
this.initializer = initializer;
}
public enum FieldOrder {
staticsBean(Modifier.STATIC | Modifier.PUBLIC,
"Constants for all javaBean properties") {
@Override
public boolean accept(JavaField field) {
return field.getName().startsWith("PROPERTY_");
}
},
staticsPublicBindings(Modifier.STATIC | Modifier.PUBLIC,
"Constants for all public bindings") {
@Override
public boolean accept(JavaField field) {
return field.getName().startsWith("BINDING_") &&
Modifier.isPublic(field.getModifiers());
}
},
staticsPrivateBindings(Modifier.STATIC | Modifier.PRIVATE,
"Constants for all none public bindings") {
@Override
public boolean accept(JavaField field) {
return field.getName().startsWith("BINDING_$") &&
Modifier.isPrivate(field.getModifiers());
}
},
staticsOthers(Modifier.STATIC, "Other static fields"),
internalFields(Modifier.PROTECTED | Modifier.PRIVATE,
"Internal states") {
private final List fields = Arrays.asList(
"delegateContext",
"$previousValues",
"$bindingSources",
"$objectMap",
"$activeBindings",
"$bindings",
"$propertyChangeSupport");
@Override
public boolean accept(JavaField field) {
return fields.contains(field.getName());
}
},
publicFields(Modifier.PUBLIC, "Public components"),
protectedFields(Modifier.PROTECTED, "Protected components"),
privateFields(Modifier.PRIVATE, "Private components"),
otherFields(0, "Other fields") {
@Override
public boolean accept(JavaField field) {
return true;
}
};
private final String header;
private final int modifier;
FieldOrder(int modifier, String header) {
this.header = JavaFileGenerator.getHeader(header);
this.modifier = modifier;
}
public String getHeader() {
return header;
}
public boolean accept(JavaField field) {
return true;
}
public boolean accept(int mod) {
return (mod & modifier) != 0;
}
public boolean accept(int mod, JavaField method) {
return accept(mod) && accept(method);
}
public static FieldOrder valueOf(JavaField method, int scope) {
for (FieldOrder o : values()) {
if (o.accept(scope, method)) {
return o;
}
}
throw new IllegalArgumentException(
"could not find a " + FieldOrder.class +
" for method " + method);
}
}
public static EnumMap> getSortedFields(List fields) {
EnumMap> result =
new EnumMap<>(FieldOrder.class);
for (FieldOrder fieldOrder : FieldOrder.values()) {
result.put(fieldOrder, new ArrayList<>());
}
EnumSet allConstants = EnumSet.allOf(FieldOrder.class);
List allFields = new ArrayList<>(fields);
int[] scopes = new int[]{Modifier.STATIC,
Modifier.PUBLIC,
Modifier.PROTECTED,
Modifier.PRIVATE
};
for (int scope : scopes) {
EnumSet constants =
getFieldOrderScope(allConstants, scope);
Iterator itMethods = allFields.iterator();
while (itMethods.hasNext()) {
JavaField method = itMethods.next();
for (FieldOrder constant : constants) {
if (constant.accept(method.getModifiers(), method)) {
result.get(constant).add(method);
itMethods.remove();
break;
}
}
}
constants.clear();
}
if (!allFields.isEmpty()) {
// probably package locale fields
result.get(FieldOrder.otherFields).addAll(allFields);
}
for (FieldOrder fieldOrder : FieldOrder.values()) {
// sort fields
Collections.sort(result.get(fieldOrder));
}
return result;
}
public static EnumSet getFieldOrderScope(EnumSet allConstants, int scope) {
EnumSet constants = EnumSet.noneOf(FieldOrder.class);
for (FieldOrder order : allConstants) {
if (order.accept(scope)) {
constants.add(order);
}
}
return constants;
}
}