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

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

There is a newer version: 1.0.0
Show newest version
package com.fitbur.bytebuddy.dynamic.scaffold.subclass;

import com.fitbur.bytebuddy.description.method.MethodDescription;
import com.fitbur.bytebuddy.description.method.MethodList;
import com.fitbur.bytebuddy.description.type.TypeDescription;
import com.fitbur.bytebuddy.dynamic.MethodTransformer;
import com.fitbur.bytebuddy.dynamic.scaffold.MethodRegistry;
import com.fitbur.bytebuddy.implementation.SuperMethodCall;
import com.fitbur.bytebuddy.implementation.attribute.MethodAttributeAppender;
import com.fitbur.bytebuddy.matcher.LatentMatcher;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

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

/**
 * A constructor strategy is responsible for creating bootstrap constructors for a
 * {@link SubclassDynamicTypeBuilder}.
 *
 * @see com.fitbur.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 tokens that describe the constructors that are to be implemented.
     */
    List extractConstructors(TypeDescription instrumentedType);

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

    /**
     * Default implementations of constructor strategies.
     */
    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
            protected List doExtractConstructors(TypeDescription superClass) {
                return Collections.emptyList();
            }

            @Override
            public MethodRegistry inject(MethodRegistry methodRegistry) {
                return methodRegistry;
            }
        },

        /**
         * 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
            protected List doExtractConstructors(TypeDescription instrumentedType) {
                TypeDescription.Generic superClass = instrumentedType.getSuperClass();
                MethodList defaultConstructors = superClass == null
                        ? new MethodList.Empty()
                        : superClass.getDeclaredMethods().filter(isConstructor().and(takesArguments(0)).and(isVisibleTo(instrumentedType)));
                if (defaultConstructors.size() == 1) {
                    return defaultConstructors.asTokenList(is(instrumentedType));
                } else {
                    throw new IllegalArgumentException(instrumentedType.getSuperClass() + " declares no constructor that is visible to " + instrumentedType);
                }
            }

            @Override
            public MethodRegistry inject(MethodRegistry methodRegistry) {
                return methodRegistry.append(new LatentMatcher.Resolved(isConstructor()),
                        new MethodRegistry.Handler.ForImplementation(SuperMethodCall.INSTANCE),
                        MethodAttributeAppender.NoOp.INSTANCE,
                        MethodTransformer.NoOp.INSTANCE);
            }
        },

        /**
         * This strategy is adding all constructors of the instrumented type's super class where each constructor is
         * directly invoking its signature-equivalent super class 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_CLASS {
            @Override
            protected List doExtractConstructors(TypeDescription instrumentedType) {
                TypeDescription.Generic superClass = instrumentedType.getSuperClass();
                return (superClass == null
                        ? new MethodList.Empty()
                        : superClass.getDeclaredMethods().filter(isConstructor().and(isVisibleTo(instrumentedType)))).asTokenList(is(instrumentedType));
            }

            @Override
            public MethodRegistry inject(MethodRegistry methodRegistry) {
                return methodRegistry.append(new LatentMatcher.Resolved(isConstructor()),
                        new MethodRegistry.Handler.ForImplementation(SuperMethodCall.INSTANCE),
                        MethodAttributeAppender.ForInstrumentedMethod.EXCLUDING_RECEIVER,
                        MethodTransformer.NoOp.INSTANCE);
            }
        },

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

            @Override
            public MethodRegistry inject(MethodRegistry methodRegistry) {
                return methodRegistry.append(new LatentMatcher.Resolved(isConstructor()),
                        new MethodRegistry.Handler.ForImplementation(SuperMethodCall.INSTANCE),
                        MethodAttributeAppender.ForInstrumentedMethod.EXCLUDING_RECEIVER,
                        MethodTransformer.NoOp.INSTANCE);
            }
        };

        @Override
        public List extractConstructors(TypeDescription instrumentedType) {
            List tokens = doExtractConstructors(instrumentedType), stripped = new ArrayList(tokens.size());
            for (MethodDescription.Token token : tokens) {
                stripped.add(new MethodDescription.Token(token.getName(),
                        token.getModifiers(),
                        token.getTypeVariableTokens(),
                        token.getReturnType(),
                        token.getParameterTokens(),
                        token.getExceptionTypes(),
                        token.getAnnotations(),
                        token.getDefaultValue(),
                        TypeDescription.Generic.UNDEFINED));
            }
            return stripped;
        }

        /**
         * Extracts the relevant method tokens of the instrumented type's constructors.
         *
         * @param instrumentedType The type for which to extract the constructors.
         * @return A list of relevant method tokens.
         */
        protected abstract List doExtractConstructors(TypeDescription instrumentedType);

        @Override
        public String toString() {
            return "ConstructorStrategy.Default." + name();
        }

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy