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

com.sun.ejb.codegen.Generator Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2021, 2023 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 com.sun.ejb.codegen;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.glassfish.pfl.dynamic.codegen.impl.ClassGeneratorImpl;
import org.glassfish.pfl.dynamic.codegen.spi.ImportList;
import org.glassfish.pfl.dynamic.codegen.spi.Wrapper;

import static com.sun.ejb.codegen.ClassGenerator.defineClass;
import static org.glassfish.pfl.dynamic.codegen.impl.CodeGenerator.generateBytecode;
import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper.DUMP_AFTER_SETUP_VISITOR;
import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper.TRACE_BYTE_CODE_GENERATION;
import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper.USE_ASM_VERIFIER;
import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._classGenerator;
import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._package;


/**
 * The base class for all code generators.
 */
public abstract class Generator {

    private static final Logger LOG = Logger.getLogger(Generator.class.getName());

    private static final String DEFAULT_PACKAGE_NAME = "";

    private final ClassLoader loader;


    /**
     * @param loader {@link ClassLoader} owning generated classes
     */
    public Generator(final ClassLoader loader) {
        this.loader = Objects.requireNonNull(loader);
    }

    /**
     * @return the name of the package of the generated class.
     */
    protected abstract String getPackageName();

    /**
     * @return name of the generated class or interface
     */
    public abstract String getGeneratedClassName();

    /**
     * @return loadable class of the same package as {@link #getGeneratedClassName()}
     */
    protected abstract Class getAnchorClass();

    /**
     * Calls {@link Wrapper} methods to configure the class definition.
     * The {@link Wrapper} uses {@link ThreadLocal} internally, so you should
     * always call {@link Wrapper#_clear()} in finally block after generation
     * to avoid leakages.
     */
    protected abstract void defineClassBody();


    /**
     * @return {@link ClassLoader} owning the generated class.
     */
    public ClassLoader getClassLoader() {
        return this.loader;
    }


    /**
     * Generates the bytecode of the configured class with the usage of the PFL tool.
     * Then uses {@link MethodHandles} or {@link ClassGenerator} to generate the class.
     * 

* WARNING: This selection depends on the classloader capabilities and JVM rules, * which change between JDK versions. * * @return {@link Class} * @throws IllegalAccessException if a reflective access error occurred */ public Class generate() throws IllegalAccessException { final String packageName = getPackageName(); if (DEFAULT_PACKAGE_NAME.equals(packageName)) { _package(); } else { _package(packageName); } final ImportList imports = Wrapper._import(); defineClassBody(); final Properties props = new Properties(); if (LOG.isLoggable(Level.FINEST)) { props.put(DUMP_AFTER_SETUP_VISITOR, "true"); props.put(TRACE_BYTE_CODE_GENERATION, "true"); props.put(USE_ASM_VERIFIER, "true"); try { final ByteArrayOutputStream baos = new ByteArrayOutputStream(); final PrintStream ps = new PrintStream(baos); Wrapper._sourceCode(ps, props); LOG.finest(baos.toString()); } catch (final Exception e) { LOG.log(Level.WARNING, "Exception generating src for logs", e); } } final ClassGeneratorImpl codeGenerator = (ClassGeneratorImpl) _classGenerator(); final byte[] bytecode = generateBytecode(codeGenerator, getClassLoader(), imports, props, System.out); return defineClass(getClassLoader(), getAnchorClass(), getPackageName(), getGeneratedClassName(), bytecode); } /** * @return the package name. */ public static String getPackageName(final String fullClassName) { final int dot = fullClassName.lastIndexOf('.'); return dot == -1 ? DEFAULT_PACKAGE_NAME : fullClassName.substring(0, dot); } /** * @return simple class name (including wrapper class and dollar sign if it is internal class) */ public static String getBaseName(final String fullClassName) { final int dot = fullClassName.lastIndexOf('.'); return dot == -1 ? fullClassName : fullClassName.substring(dot + 1); } /** * Returns full qualified class name. * * @param packageName the package name * @param baseName the base (simple) class name * @return the full qualified class name */ public static String getFullClassName(final String packageName, final String baseName) { if (DEFAULT_PACKAGE_NAME.equals(packageName)) { return baseName; } return packageName + "." + baseName; } /** * Remove duplicates from method array. *

* Duplicates will arise if a class/intf and super-class/intf * define methods with the same signature. Potentially the * throws clauses of the methods may be different (note Java * requires that the superclass/intf method have a superset of the * exceptions in the derived method). * * @param methods the methods array without duplicates * @return methods which can be generated in an interface */ protected Method[] removeRedundantMethods(final Method[] methods) { final List nodups = new ArrayList<>(); for (final Method method : methods) { boolean duplicationDetected = false; final List previousResult = new ArrayList<>(nodups); for (final Method alreadyProcessed : previousResult) { // m1 and m2 are duplicates if they have the same signature // (name and same parameters). if (!method.getName().equals(alreadyProcessed.getName())) { continue; } if (!haveSameParams(method, alreadyProcessed)) { continue; } duplicationDetected = true; // Select which of the duplicate methods to generate // code for: choose the one that is lower in the // inheritance hierarchy: this ensures that the generated // method will compile. if (alreadyProcessed.getDeclaringClass().isAssignableFrom(method.getDeclaringClass())) { // alreadyProcessedMethod is a superclass/intf of method, // so replace it with more concrete method nodups.remove(alreadyProcessed); nodups.add(method); } break; } if (!duplicationDetected) { nodups.add(method); } } return nodups.toArray(Method[]::new); } private boolean haveSameParams(final Method method1, final Method method2) { final Class[] m1parms = method1.getParameterTypes(); final Class[] m2parms = method2.getParameterTypes(); if (m1parms.length != m2parms.length) { return false; } for (int i = 0; i < m2parms.length; i++) { if (m1parms[i] != m2parms[i]) { return false; } } return true; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy