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

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

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy