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

com.fitbur.bytebuddy.implementation.bytecode.assign.primitive.PrimitiveUnboxingDelegate Maven / Gradle / Ivy

There is a newer version: 1.0.0
Show newest version
package com.fitbur.bytebuddy.implementation.bytecode.assign.primitive;

import com.fitbur.bytebuddy.description.type.TypeDefinition;
import com.fitbur.bytebuddy.description.type.TypeDescription;
import com.fitbur.bytebuddy.implementation.Implementation;
import com.fitbur.bytebuddy.implementation.bytecode.StackManipulation;
import com.fitbur.bytebuddy.implementation.bytecode.StackSize;
import com.fitbur.bytebuddy.implementation.bytecode.assign.Assigner;
import com.fitbur.bytebuddy.jar.asm.MethodVisitor;
import com.fitbur.bytebuddy.jar.asm.Opcodes;

/**
 * This delegate is responsible for unboxing a wrapper type to their primitive equivalents.
 */
public enum PrimitiveUnboxingDelegate implements StackManipulation {

    /**
     * The unboxing delegate for {@code Boolean} types.
     */
    BOOLEAN(Boolean.class, boolean.class, StackSize.ZERO, "booleanValue", "()Z"),

    /**
     * The unboxing delegate for {@code Byte} types.
     */
    BYTE(Byte.class, byte.class, StackSize.ZERO, "byteValue", "()B"),

    /**
     * The unboxing delegate for {@code Short} types.
     */
    SHORT(Short.class, short.class, StackSize.ZERO, "shortValue", "()S"),

    /**
     * The unboxing delegate for {@code Character} types.
     */
    CHARACTER(Character.class, char.class, StackSize.ZERO, "charValue", "()C"),

    /**
     * The unboxing delegate for {@code Integer} types.
     */
    INTEGER(Integer.class, int.class, StackSize.ZERO, "intValue", "()I"),

    /**
     * The unboxing delegate for {@code Long} types.
     */
    LONG(Long.class, long.class, StackSize.SINGLE, "longValue", "()J"),

    /**
     * The unboxing delegate for {@code Float} types.
     */
    FLOAT(Float.class, float.class, StackSize.ZERO, "floatValue", "()F"),

    /**
     * The unboxing delegate for {@code Double} types.
     */
    DOUBLE(Double.class, double.class, StackSize.SINGLE, "doubleValue", "()D");

    /**
     * The wrapper type of the represented primitive type.
     */
    private final TypeDescription wrapperType;

    /**
     * The represented primitive type.
     */
    private final TypeDescription primitiveType;

    /**
     * The size increase after a wrapper type was unwrapped.
     */
    private final Size size;

    /**
     * The name of the method for unboxing a wrapper value to its primitive value.
     */
    private final String unboxingMethodName;

    /**
     * The descriptor of the method for unboxing a wrapper value to its primitive value.
     */
    private final String unboxingMethodDescriptor;

    /**
     * Creates a new primitive unboxing delegate.
     *
     * @param wrapperType              The wrapper type of the represented primitive type.
     * @param primitiveType            The represented primitive type.
     * @param sizeDifference           The size difference between the wrapper type and its primitive value.
     * @param unboxingMethodName       The name of the method for unboxing a wrapper value to its primitive value.
     * @param unboxingMethodDescriptor The descriptor of the method for unboxing a wrapper value to its primitive value.
     */
    PrimitiveUnboxingDelegate(Class wrapperType,
                              Class primitiveType,
                              StackSize sizeDifference,
                              String unboxingMethodName,
                              String unboxingMethodDescriptor) {
        this.size = sizeDifference.toIncreasingSize();
        this.wrapperType = new TypeDescription.ForLoadedType(wrapperType);
        this.primitiveType = new TypeDescription.ForLoadedType(primitiveType);
        this.unboxingMethodName = unboxingMethodName;
        this.unboxingMethodDescriptor = unboxingMethodDescriptor;
    }

    /**
     * Locates a primitive unboxing delegate for a given primitive type.
     *
     * @param typeDescription A description of the primitive type.
     * @return A corresponding primitive unboxing delegate.
     */
    protected static PrimitiveUnboxingDelegate forPrimitive(TypeDescription.Generic typeDescription) {
        if (typeDescription.represents(boolean.class)) {
            return BOOLEAN;
        } else if (typeDescription.represents(byte.class)) {
            return BYTE;
        } else if (typeDescription.represents(short.class)) {
            return SHORT;
        } else if (typeDescription.represents(char.class)) {
            return CHARACTER;
        } else if (typeDescription.represents(int.class)) {
            return INTEGER;
        } else if (typeDescription.represents(long.class)) {
            return LONG;
        } else if (typeDescription.represents(float.class)) {
            return FLOAT;
        } else if (typeDescription.represents(double.class)) {
            return DOUBLE;
        } else {
            throw new IllegalArgumentException("Expected non-void primitive type instead of " + typeDescription);
        }
    }

    /**
     * Creates an unboxing responsible that is capable of unboxing a wrapper type.
     * 
    *
  1. If the reference type represents a wrapper type, the wrapper type will simply be unboxed.
  2. *
  3. If the reference type does not represent a wrapper type, the wrapper type will be inferred by the primitive target * type that is later given to the * {@link com.fitbur.bytebuddy.implementation.bytecode.assign.primitive.PrimitiveUnboxingDelegate.UnboxingResponsible} * in order to then check if the given type is assignable to the inferred wrapper type.
  4. *
* * @param typeDefinition A non-primitive type. * @return An unboxing responsible capable of performing an unboxing operation while considering a further assignment * of the unboxed value. */ public static UnboxingResponsible forReferenceType(TypeDefinition typeDefinition) { if (typeDefinition.isPrimitive()) { throw new IllegalArgumentException("Expected reference type instead of " + typeDefinition); } else if (typeDefinition.represents(Boolean.class)) { return ExplicitlyTypedUnboxingResponsible.BOOLEAN; } else if (typeDefinition.represents(Byte.class)) { return ExplicitlyTypedUnboxingResponsible.BYTE; } else if (typeDefinition.represents(Short.class)) { return ExplicitlyTypedUnboxingResponsible.SHORT; } else if (typeDefinition.represents(Character.class)) { return ExplicitlyTypedUnboxingResponsible.CHARACTER; } else if (typeDefinition.represents(Integer.class)) { return ExplicitlyTypedUnboxingResponsible.INTEGER; } else if (typeDefinition.represents(Long.class)) { return ExplicitlyTypedUnboxingResponsible.LONG; } else if (typeDefinition.represents(Float.class)) { return ExplicitlyTypedUnboxingResponsible.FLOAT; } else if (typeDefinition.represents(Double.class)) { return ExplicitlyTypedUnboxingResponsible.DOUBLE; } else { return new ImplicitlyTypedUnboxingResponsible(typeDefinition.asGenericType()); } } /** * Returns the wrapper type that this unboxing delegate represents. * * @return A generic version of this delegate's wrapper type. */ protected TypeDescription.Generic getWrapperType() { return wrapperType.asGenericType(); } @Override public boolean isValid() { return true; } @Override public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) { methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, wrapperType.asErasure().getInternalName(), unboxingMethodName, unboxingMethodDescriptor, false); return size; } @Override public String toString() { return "PrimitiveUnboxingDelegate." + name(); } /** * An explicitly types unboxing responsible is applied for directly unboxing a wrapper type. */ protected enum ExplicitlyTypedUnboxingResponsible implements UnboxingResponsible { /** * An unboxing responsible for unboxing a {@link java.lang.Boolean} type. */ BOOLEAN(PrimitiveUnboxingDelegate.BOOLEAN), /** * An unboxing responsible for unboxing a {@link java.lang.Byte} type. */ BYTE(PrimitiveUnboxingDelegate.BYTE), /** * An unboxing responsible for unboxing a {@link java.lang.Short} type. */ SHORT(PrimitiveUnboxingDelegate.SHORT), /** * An unboxing responsible for unboxing a {@link java.lang.Character} type. */ CHARACTER(PrimitiveUnboxingDelegate.CHARACTER), /** * An unboxing responsible for unboxing a {@link java.lang.Integer} type. */ INTEGER(PrimitiveUnboxingDelegate.INTEGER), /** * An unboxing responsible for unboxing a {@link java.lang.Long} type. */ LONG(PrimitiveUnboxingDelegate.LONG), /** * An unboxing responsible for unboxing a {@link java.lang.Float} type. */ FLOAT(PrimitiveUnboxingDelegate.FLOAT), /** * An unboxing responsible for unboxing a {@link java.lang.Double} type. */ DOUBLE(PrimitiveUnboxingDelegate.DOUBLE); /** * The primitive unboxing delegate for handling the given wrapper type. */ private final PrimitiveUnboxingDelegate primitiveUnboxingDelegate; /** * Creates a new explicitly typed unboxing responsible. * * @param primitiveUnboxingDelegate The primitive unboxing delegate for handling the given wrapper type. */ ExplicitlyTypedUnboxingResponsible(PrimitiveUnboxingDelegate primitiveUnboxingDelegate) { this.primitiveUnboxingDelegate = primitiveUnboxingDelegate; } @Override public StackManipulation assignUnboxedTo(TypeDescription.Generic targetType, Assigner assigner, Assigner.Typing typing) { return new Compound( primitiveUnboxingDelegate, PrimitiveWideningDelegate.forPrimitive(primitiveUnboxingDelegate.primitiveType).widenTo(targetType)); } @Override public String toString() { return "PrimitiveUnboxingDelegate.ExplicitlyTypedUnboxingResponsible." + name(); } } /** * Implementations represent an unboxing delegate that is able to perform the unboxing operation. */ public interface UnboxingResponsible { /** * Attempts to unbox the represented type in order to assign the unboxed value to the given target type * while using the assigner that is provided by the method call. * * @param target The type that is the desired outcome of the assignment. * @param assigner The assigner used to assign the unboxed type to the target type. * @param typing Determines if a type-casting should be attempted for incompatible types. * @return A stack manipulation representing this assignment if such an assignment is possible. An illegal * assignment otherwise. */ StackManipulation assignUnboxedTo(TypeDescription.Generic target, Assigner assigner, Assigner.Typing typing); } /** * An unboxing responsible for an implicitly typed value. This implementation is applied for source types that * were not found to be of a given wrapper type. Instead, this unboxing responsible tries to assign the * source type to the primitive target type's wrapper type before performing an unboxing operation. */ protected static class ImplicitlyTypedUnboxingResponsible implements UnboxingResponsible { /** * The original type which should be unboxed but is not of any known wrapper type. */ private final TypeDescription.Generic originalType; /** * Creates a new implicitly typed unboxing responsible. * * @param originalType The original type which should be unboxed but is not of any known wrapper type. */ protected ImplicitlyTypedUnboxingResponsible(TypeDescription.Generic originalType) { this.originalType = originalType; } @Override public StackManipulation assignUnboxedTo(TypeDescription.Generic target, Assigner assigner, Assigner.Typing typing) { PrimitiveUnboxingDelegate primitiveUnboxingDelegate = PrimitiveUnboxingDelegate.forPrimitive(target); return new Compound( assigner.assign(originalType, primitiveUnboxingDelegate.getWrapperType(), typing), primitiveUnboxingDelegate); } @Override public boolean equals(Object other) { return this == other || !(other == null || getClass() != other.getClass()) && originalType.equals(((ImplicitlyTypedUnboxingResponsible) other).originalType); } @Override public int hashCode() { return originalType.hashCode(); } @Override public String toString() { return "PrimitiveUnboxingDelegate.ImplicitlyTypedUnboxingResponsible{originalType=" + originalType + '}'; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy