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

com.ui4j.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy Maven / Gradle / Ivy

The newest version!
package com.ui4j.bytebuddy.dynamic.scaffold.subclass;

import com.ui4j.bytebuddy.dynamic.scaffold.MethodRegistry;
import com.ui4j.bytebuddy.instrumentation.SuperMethodCall;
import com.ui4j.bytebuddy.instrumentation.attribute.MethodAttributeAppender;
import com.ui4j.bytebuddy.instrumentation.method.MethodDescription;
import com.ui4j.bytebuddy.instrumentation.method.MethodList;
import com.ui4j.bytebuddy.instrumentation.type.TypeDescription;

import static com.ui4j.bytebuddy.matcher.ElementMatchers.*;

/**
 * A constructor strategy is responsible for creating bootstrap constructors for a
 * {@link SubclassDynamicTypeBuilder}.
 *
 * @see com.ui4j.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy.Default
 */
public interface ConstructorStrategy {

    /**
     * Extracts constructors for a given super type. The extracted constructor signatures will then be imitated by the
     * created dynamic type.
     *
     * @param instrumentedType The type for which the constructors should be created.
     * @return A list of constructor descriptions which will be mimicked by the instrumented type of which
     * the {@code superType} is the direct super type of the instrumented type.
     */
    MethodList extractConstructors(TypeDescription instrumentedType);

    /**
     * Returns a method registry that is capable of creating byte code for the constructors that were
     * provided by the
     * {@link com.ui4j.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy#extractConstructors(com.ui4j.bytebuddy.instrumentation.type.TypeDescription)}
     * method of this instance.
     *
     * @param methodRegistry                        The original method registry.
     * @param defaultMethodAttributeAppenderFactory The default method attribute appender factory.
     * @return A method registry that is capable of providing byte code for the constructors that were added by
     * this strategy.
     */
    MethodRegistry inject(MethodRegistry methodRegistry,
                          MethodAttributeAppender.Factory defaultMethodAttributeAppenderFactory);

    /**
     * Default implementations of constructor strategies.
     */
    static enum Default implements ConstructorStrategy {

        /**
         * This strategy is adding no constructors such that the instrumented type will by default not have any. This
         * is legal by Java byte code requirements. However, if no constructor is added manually if this strategy is
         * applied, the type is not constructable without using JVM non-public functionality.
         */
        NO_CONSTRUCTORS {
            @Override
            public MethodList extractConstructors(TypeDescription superType) {
                return new MethodList.Empty();
            }
        },

        /**
         * This strategy is adding a default constructor that calls it's super types default constructor. If no such
         * constructor is defined, an {@link IllegalArgumentException} is thrown. Note that the default constructor
         * needs to be visible to its sub type for this strategy to work.
         */
        DEFAULT_CONSTRUCTOR {
            @Override
            public MethodList extractConstructors(TypeDescription instrumentedType) {
                TypeDescription superType = instrumentedType.getSupertype();
                MethodList methodList = superType == null
                        ? new MethodList.Empty()
                        : superType.getDeclaredMethods()
                        .filter(isConstructor().and(takesArguments(0))
                                .and(isVisibleTo(instrumentedType)));
                if (methodList.size() == 1) {
                    return methodList;
                } else {
                    throw new IllegalArgumentException(String.format("%s does not declare a default constructor that " +
                            "is visible to %s", instrumentedType.getSupertype(), instrumentedType));
                }
            }
        },

        /**
         * This strategy is adding all constructors of the instrumented type's super type where each constructor is
         * directly invoking its signature-equivalent super type constructor. Only constructors that are visible to the
         * instrumented type are added, i.e. package-private constructors are only added if the super type is defined
         * in the same package as the instrumented type and private constructors are always skipped.
         */
        IMITATE_SUPER_TYPE {
            @Override
            public MethodList extractConstructors(TypeDescription instrumentedType) {
                TypeDescription superType = instrumentedType.getSupertype();
                return superType == null
                        ? new MethodList.Empty()
                        : superType.getDeclaredMethods()
                        .filter(isConstructor().and(isVisibleTo(instrumentedType)));
            }
        },

        /**
         * This strategy is adding all constructors of the instrumented type's super type where each constructor is
         * directly invoking its signature-equivalent super type constructor. Only {@code public} constructors are
         * added.
         */
        IMITATE_SUPER_TYPE_PUBLIC {
            @Override
            public MethodList extractConstructors(TypeDescription instrumentedType) {
                TypeDescription superType = instrumentedType.getSupertype();
                return superType == null
                        ? new MethodList.Empty()
                        : superType.getDeclaredMethods().filter(isPublic().and(isConstructor()));
            }
        };

        @Override
        public MethodRegistry inject(MethodRegistry methodRegistry,
                                     MethodAttributeAppender.Factory defaultMethodAttributeAppenderFactory) {
            switch (this) {
                case NO_CONSTRUCTORS:
                    return methodRegistry;
                case DEFAULT_CONSTRUCTOR:
                case IMITATE_SUPER_TYPE:
                case IMITATE_SUPER_TYPE_PUBLIC:
                    return methodRegistry.append(new MethodRegistry.LatentMethodMatcher.Simple(isConstructor()),
                            SuperMethodCall.INSTANCE,
                            defaultMethodAttributeAppenderFactory);
                default:
                    throw new AssertionError();
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy