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

org.glassfish.apf.impl.ComponentDefinition Maven / Gradle / Ivy

There is a newer version: 8.0.0-JDK17-M7
Show newest version
/*
 * Copyright (c) 2022 Contributors to the Eclipse Foundation
 * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package org.glassfish.apf.impl;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.glassfish.apf.ComponentInfo;

import static java.lang.reflect.Modifier.isPrivate;
import static java.lang.reflect.Modifier.isProtected;
import static java.lang.reflect.Modifier.isPublic;


/**
 * This class represents the view of a class from annotation.
 *
 * @author Shing Wai Chan
 */
public class ComponentDefinition implements ComponentInfo {

    private static final Set EXCLUDED_FROM_ANNOTATION_PROCESSING = Collections.unmodifiableSet(new HashSet<>(Set.of(
        "jakarta.servlet.GenericServlet",
        "jakarta.servlet.http.HttpServlet",
        "org.glassfish.wasp.servlet.JspServlet",
        "org.apache.catalina.servlets.DefaultServlet"
    )));

    private final Class clazz;
    private final List> constructors = new ArrayList<>();
    private final List> classes = new ArrayList<>();
    private final List fields = new ArrayList<>();
    private final Map methodMap = new HashMap<>();


    public ComponentDefinition(Class clazz) {
        this.clazz = clazz;
        constructClassList();
        initializeConstructors();
        initializeFields();
        initializeMethods();
    }


    @Override
    public Field[] getFields() {
        return fields.toArray(Field[]::new);
    }


    @Override
    public Method[] getMethods() {
        return methodMap.values().toArray(Method[]::new);
    }


    @Override
    public Constructor[] getConstructors() {
        return constructors.toArray(Constructor[]::new);
    }


    private void constructClassList() {
        // check whether this class is in the skip list
        if (!isExcludedFromAnnotationProcessing(clazz)) {
            classes.add(clazz);
        }
        Class parent = clazz;
        while ((parent = parent.getSuperclass()) != null) {
            if (!isExcludedFromAnnotationProcessing(parent)) {
                classes.add(0, parent);
            }
        }
    }


    /**
     * In P.148 of "The Java Langugage Specification 2/e",
     * Constructors, static initializers, and instance initializers are not
     * members and therefore not inherited.
     */
    private void initializeConstructors() {
        for (Class cl : classes) {
            for (Constructor constr : cl.getConstructors()) {
                constructors.add(constr);
            }
        }
    }


    private void initializeFields() {
        for (Class cl : classes) {
            for (Field f : cl.getDeclaredFields()) {
                fields.add(f);
            }
        }
    }


    private void initializeMethods() {
        for (Class cl : classes) {
            for (Method method : cl.getDeclaredMethods()) {
                if (!method.isBridge()) {
                    methodMap.put(new MethodKey(method), method);
                }
            }
        }
    }


    /**
     * Check whether a certain class can skip annotation processing
     *
     * @return true if the class should not be processed
     */
    static boolean isExcludedFromAnnotationProcessing(Class clazz) {
        if (clazz.getPackage() == null) {
            return false;
        }
        if (clazz.getPackage().getName().startsWith("java.lang")) {
            return true;
        }
        return EXCLUDED_FROM_ANNOTATION_PROCESSING.contains(clazz.getCanonicalName());
    }


    /**
     * MethodKey represents a method for the annotation's point of view.
     * 

* The class doesn't matter in the {@link #hashCode()}, but it does matter * in {@link #equals(Object)} to resolve the visibility of the method. */ private static class MethodKey { private final Method m; private final Package classPackage; private final String className; private final int hashCode; private MethodKey(Method m) { this.m = m; this.className = m.getDeclaringClass().getName(); this.classPackage = m.getDeclaringClass().getPackage(); this.hashCode = m.getName().hashCode(); } @Override public int hashCode() { return hashCode; } /** * This equals method is defined in terms of inheritance overriding. * We depends on java compiler to rule out irrelvant cases here. * * @return true for overriding and false otherwise */ @Override public boolean equals(Object o) { if (!(o instanceof MethodKey)) { return false; } MethodKey mk2 = (MethodKey) o; Method m2 = mk2.m; if (m.getName().equals(m2.getName()) && Arrays.equals(m.getParameterTypes(), m2.getParameterTypes())) { int modifiers2 = m2.getModifiers(); boolean isSamePackage = hasSamePackage(mk2); if (isPrivate(m.getModifiers())) { return isPrivate(modifiers2) && isSamePackage && className.equals(mk2.className); } return isPublic(modifiers2) || isProtected(modifiers2) || (isPackageProtected(modifiers2) && isSamePackage); } return false; } private boolean hasSamePackage(MethodKey mk2) { // Note: Package doesn't define equals if (classPackage == mk2.classPackage) { return true; } return classPackage != null && mk2.classPackage != null && classPackage.getName().equals(mk2.classPackage.getName()); } private static boolean isPackageProtected(int modifiers) { return !isPublic(modifiers) && !isProtected(modifiers) && !isPrivate(modifiers); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy