All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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




© 2015 - 2024 Weber Informatics LLC | Privacy Policy