/*
 * Copyright 2014 - 2019 Rafael Winterhalter
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.bytebuddy.implementation;

import net.bytebuddy.build.HashCodeAndEqualsPlugin;
import net.bytebuddy.description.field.FieldDescription;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.scaffold.InstrumentedType;
import net.bytebuddy.implementation.bytecode.ByteCodeAppender;
import net.bytebuddy.implementation.bytecode.Duplication;
import net.bytebuddy.implementation.bytecode.StackManipulation;
import net.bytebuddy.implementation.bytecode.TypeCreation;
import net.bytebuddy.implementation.bytecode.constant.TextConstant;
import net.bytebuddy.implementation.bytecode.member.FieldAccess;
import net.bytebuddy.implementation.bytecode.member.MethodInvocation;
import net.bytebuddy.implementation.bytecode.member.MethodReturn;
import net.bytebuddy.implementation.bytecode.member.MethodVariableAccess;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.matcher.ElementMatchers;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

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

import static net.bytebuddy.matcher.ElementMatchers.*;

An implementation of Object.toString() that concatenates the String representation of all fields that are declared by a class.
/** * An implementation of {@link Object#toString()} that concatenates the {@link String} representation of all fields that are declared by a class. */
@HashCodeAndEqualsPlugin.Enhance public class ToStringMethod implements Implementation {
The StringBuilder(String) constructor.
/** * The {@link StringBuilder#StringBuilder(String)} constructor. */
private static final MethodDescription.InDefinedShape STRING_BUILDER_CONSTRUCTOR = TypeDescription.ForLoadedType.of(StringBuilder.class) .getDeclaredMethods() .filter(isConstructor().and(ElementMatchers.takesArguments(String.class))) .getOnly(); /** * The {@link StringBuilder#toString()} method. */ private static final MethodDescription.InDefinedShape TO_STRING = TypeDescription.ForLoadedType.of(StringBuilder.class) .getDeclaredMethods() .filter(isToString()) .getOnly();
A resolver for the prefix of a String representation.
/** * A resolver for the prefix of a {@link String} representation. */
private final PrefixResolver prefixResolver;
A token that is added between the prefix and the first field value.
/** * A token that is added between the prefix and the first field value. */
private final String start;
A token that is added after the last field value.
/** * A token that is added after the last field value. */
private final String end;
A token that is added between two field values.
/** * A token that is added between two field values. */
private final String separator;
A token that is added between a field's name and its value.
/** * A token that is added between a field's name and its value. */
private final String definer;
A filter that determines what fields to ignore.
/** * A filter that determines what fields to ignore. */
private final ElementMatcher.Junction<? super FieldDescription.InDefinedShape> ignored;
Creates a new toString implementation.
Params:
  • prefixResolver – A resolver for the prefix of a String representation.
/** * Creates a new {@code toString} implementation. * * @param prefixResolver A resolver for the prefix of a {@link String} representation. */
protected ToStringMethod(PrefixResolver prefixResolver) { this(prefixResolver, "{", "}", ", ", "=", none()); }
Creates a new toString implementation.
Params:
  • prefixResolver – A resolver for the prefix of a String representation.
  • start – A token that is added between the prefix and the first field value.
  • end – A token that is added after the last field value.
  • separator – A token that is added between two field values.
  • definer – A token that is added between a field's name and its value.
  • ignored – A filter that determines what fields to ignore.
/** * Creates a new {@code toString} implementation. * * @param prefixResolver A resolver for the prefix of a {@link String} representation. * @param start A token that is added between the prefix and the first field value. * @param end A token that is added after the last field value. * @param separator A token that is added between two field values. * @param definer A token that is added between a field's name and its value. * @param ignored A filter that determines what fields to ignore. */
private ToStringMethod(PrefixResolver prefixResolver, String start, String end, String separator, String definer, ElementMatcher.Junction<? super FieldDescription.InDefinedShape> ignored) { this.prefixResolver = prefixResolver; this.start = start; this.end = end; this.separator = separator; this.definer = definer; this.ignored = ignored; }
Creates a Object.toString() implementation that is prefixed by the fully qualified class name of the instrumented type.
Returns:A Object.toString() implementation that is prefixed by the fully qualified class name of the instrumented type.
/** * Creates a {@link Object#toString()} implementation that is prefixed by the fully qualified class name of the instrumented type. * * @return A {@link Object#toString()} implementation that is prefixed by the fully qualified class name of the instrumented type. */
public static ToStringMethod prefixedByFullyQualifiedClassName() { return prefixedBy(PrefixResolver.Default.FULLY_QUALIFIED_CLASS_NAME); }
Creates a Object.toString() implementation that is prefixed by the canonical class name of the instrumented type.
Returns:A Object.toString() implementation that is prefixed by the canonical class name of the instrumented type.
/** * Creates a {@link Object#toString()} implementation that is prefixed by the canonical class name of the instrumented type. * * @return A {@link Object#toString()} implementation that is prefixed by the canonical class name of the instrumented type. */
public static ToStringMethod prefixedByCanonicalClassName() { return prefixedBy(PrefixResolver.Default.CANONICAL_CLASS_NAME); }
Creates a Object.toString() implementation that is prefixed by the simple class name of the instrumented type.
Returns:A Object.toString() implementation that is prefixed by the simple class name of the instrumented type.
/** * Creates a {@link Object#toString()} implementation that is prefixed by the simple class name of the instrumented type. * * @return A {@link Object#toString()} implementation that is prefixed by the simple class name of the instrumented type. */
public static ToStringMethod prefixedBySimpleClassName() { return prefixedBy(PrefixResolver.Default.SIMPLE_CLASS_NAME); }
Creates a Object.toString() implementation that is prefixed by the supplied string.
Params:
  • prefix – The prefix to use.
Returns:A Object.toString() implementation that is prefixed by the supplied string.
/** * Creates a {@link Object#toString()} implementation that is prefixed by the supplied string. * * @param prefix The prefix to use. * @return A {@link Object#toString()} implementation that is prefixed by the supplied string. */
public static ToStringMethod prefixedBy(String prefix) { if (prefix == null) { throw new IllegalArgumentException("Prefix cannot be null"); } return prefixedBy(new PrefixResolver.ForFixedValue(prefix)); }
Creates a Object.toString() implementation that is prefixed by the string that is supplied by the given prefix resolver.
Params:
  • prefixResolver – The prefix resolver to use.
Returns:A Object.toString() implementation that is prefixed by the string that is supplied by the given prefix resolver.
/** * Creates a {@link Object#toString()} implementation that is prefixed by the string that is supplied by the given prefix resolver. * * @param prefixResolver The prefix resolver to use. * @return A {@link Object#toString()} implementation that is prefixed by the string that is supplied by the given prefix resolver. */
public static ToStringMethod prefixedBy(PrefixResolver prefixResolver) { return new ToStringMethod(prefixResolver); }
Returns a new version of this toString method implementation that ignores the specified fields additionally to any previously specified fields.
Params:
  • ignored – A matcher to specify any fields that should be ignored.
Returns:A new version of this toString method implementation that also ignores any fields matched by the provided matcher.
/** * Returns a new version of this toString method implementation that ignores the specified fields additionally to any * previously specified fields. * * @param ignored A matcher to specify any fields that should be ignored. * @return A new version of this toString method implementation that also ignores any fields matched by the provided matcher. */
public ToStringMethod withIgnoredFields(ElementMatcher<? super FieldDescription.InDefinedShape> ignored) { return new ToStringMethod(prefixResolver, start, end, separator, definer, this.ignored.<FieldDescription.InDefinedShape>or(ignored)); }
Changes the tokens used for the Object.toString() implementation.
Params:
  • start – A token that is added between the prefix and the first field value.
  • end – A token that is added after the last field value.
  • separator – A token that is added between two field values.
  • definer – A token that is added between two field values.
Returns:A new instance of this implementation that uses the supplied tokens.
/** * Changes the tokens used for the {@link Object#toString()} implementation. * * @param start A token that is added between the prefix and the first field value. * @param end A token that is added after the last field value. * @param separator A token that is added between two field values. * @param definer A token that is added between two field values. * @return A new instance of this implementation that uses the supplied tokens. */
public Implementation withTokens(String start, String end, String separator, String definer) { if (start == null || end == null || separator == null || definer == null) { throw new IllegalArgumentException("Token values cannot be null"); } return new ToStringMethod(prefixResolver, start, end, separator, definer, ignored); }
{@inheritDoc}
/** * {@inheritDoc} */
public InstrumentedType prepare(InstrumentedType instrumentedType) { return instrumentedType; }
{@inheritDoc}
/** * {@inheritDoc} */
public Appender appender(Target implementationTarget) { if (implementationTarget.getInstrumentedType().isInterface()) { throw new IllegalStateException("Cannot implement meaningful toString method for " + implementationTarget.getInstrumentedType()); } String prefix = prefixResolver.resolve(implementationTarget.getInstrumentedType()); if (prefix == null) { throw new IllegalStateException("Prefix for toString method cannot be null"); } return new Appender(prefix, start, end, separator, definer, implementationTarget.getInstrumentedType().getDeclaredFields().filter(not(isStatic().or(ignored)))); }
An appender to implement ToStringMethod.
/** * An appender to implement {@link ToStringMethod}. */
@HashCodeAndEqualsPlugin.Enhance protected static class Appender implements ByteCodeAppender {
The prefix to use.
/** * The prefix to use. */
private final String prefix;
A token that is added between the prefix and the first field value.
/** * A token that is added between the prefix and the first field value. */
private final String start;
A token that is added after the last field value.
/** * A token that is added after the last field value. */
private final String end;
A token that is added between two field values.
/** * A token that is added between two field values. */
private final String separator;
A token that is added between a field's name and its value.
/** * A token that is added between a field's name and its value. */
private final String definer;
The list of fields to include in the Object.toString() implementation.
/** * The list of fields to include in the {@link Object#toString()} implementation. */
private final List<? extends FieldDescription.InDefinedShape> fieldDescriptions;
Creates a new appender.
Params:
  • prefix – The prefix to use.
  • start – A token that is added between the prefix and the first field value.
  • end – A token that is added after the last field value.
  • separator – A token that is added between two field values.
  • definer – A token that is added between a field's name and its value.
  • fieldDescriptions – The list of fields to include in the Object.toString() implementation.
/** * Creates a new appender. * * @param prefix The prefix to use. * @param start A token that is added between the prefix and the first field value. * @param end A token that is added after the last field value. * @param separator A token that is added between two field values. * @param definer A token that is added between a field's name and its value. * @param fieldDescriptions The list of fields to include in the {@link Object#toString()} implementation. */
protected Appender(String prefix, String start, String end, String separator, String definer, List<? extends FieldDescription.InDefinedShape> fieldDescriptions) { this.prefix = prefix; this.start = start; this.end = end; this.separator = separator; this.definer = definer; this.fieldDescriptions = fieldDescriptions; }
{@inheritDoc}
/** * {@inheritDoc} */
public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) { if (instrumentedMethod.isStatic()) { throw new IllegalStateException("toString method must not be static: " + instrumentedMethod); } else if (!instrumentedMethod.getReturnType().asErasure().isAssignableFrom(String.class)) { throw new IllegalStateException("toString method does not return String-compatible type: " + instrumentedMethod); } List<StackManipulation> stackManipulations = new ArrayList<StackManipulation>(Math.max(0, fieldDescriptions.size() * 7 - 2) + 10); stackManipulations.add(TypeCreation.of(TypeDescription.ForLoadedType.of(StringBuilder.class))); stackManipulations.add(Duplication.SINGLE); stackManipulations.add(new TextConstant(prefix)); stackManipulations.add(MethodInvocation.invoke(STRING_BUILDER_CONSTRUCTOR)); stackManipulations.add(new TextConstant(start)); stackManipulations.add(ValueConsumer.STRING); boolean first = true; for (FieldDescription.InDefinedShape fieldDescription : fieldDescriptions) { if (first) { first = false; } else { stackManipulations.add(new TextConstant(separator)); stackManipulations.add(ValueConsumer.STRING); } stackManipulations.add(new TextConstant(fieldDescription.getName() + definer)); stackManipulations.add(ValueConsumer.STRING); stackManipulations.add(MethodVariableAccess.loadThis()); stackManipulations.add(FieldAccess.forField(fieldDescription).read()); stackManipulations.add(ValueConsumer.of(fieldDescription.getType().asErasure())); } stackManipulations.add(new TextConstant(end)); stackManipulations.add(ValueConsumer.STRING); stackManipulations.add(MethodInvocation.invoke(TO_STRING)); stackManipulations.add(MethodReturn.REFERENCE); return new Size(new StackManipulation.Compound(stackManipulations).apply(methodVisitor, implementationContext).getMaximalSize(), instrumentedMethod.getStackSize()); } }
A prefix resolver is responsible for providing a value that is prepended to a Object.toString() implementation.
/** * A prefix resolver is responsible for providing a value that is prepended to a {@link Object#toString()} implementation. */
public interface PrefixResolver {
Resolves the prefixed value.
Params:
  • instrumentedType – The instrumented type.
Returns:The value to be prefixed.
/** * Resolves the prefixed value. * * @param instrumentedType The instrumented type. * @return The value to be prefixed. */
String resolve(TypeDescription instrumentedType);
Default implementations for a prefix resolver.
/** * Default implementations for a prefix resolver. */
enum Default implements PrefixResolver {
A prefix resolver for the instrumented type's fully qualified class name.
/** * A prefix resolver for the instrumented type's fully qualified class name. */
FULLY_QUALIFIED_CLASS_NAME {
{@inheritDoc}
/** {@inheritDoc} */
public String resolve(TypeDescription instrumentedType) { return instrumentedType.getName(); } },
A prefix resolver for the instrumented type's fully qualified class name.
/** * A prefix resolver for the instrumented type's fully qualified class name. */
CANONICAL_CLASS_NAME {
{@inheritDoc}
/** {@inheritDoc} */
public String resolve(TypeDescription instrumentedType) { return instrumentedType.getCanonicalName(); } },
A prefix resolver for the instrumented type's simple class name.
/** * A prefix resolver for the instrumented type's simple class name. */
SIMPLE_CLASS_NAME {
{@inheritDoc}
/** {@inheritDoc} */
public String resolve(TypeDescription instrumentedType) { return instrumentedType.getSimpleName(); } } }
A prefix resolver that returns a fixed value.
/** * A prefix resolver that returns a fixed value. */
@HashCodeAndEqualsPlugin.Enhance class ForFixedValue implements PrefixResolver {
The prefix to prepend.
/** * The prefix to prepend. */
private final String prefix;
Creates a new prefix resolver that returns a fixed value.
Params:
  • prefix – The prefix to prepend.
/** * Creates a new prefix resolver that returns a fixed value. * * @param prefix The prefix to prepend. */
protected ForFixedValue(String prefix) { this.prefix = prefix; }
{@inheritDoc}
/** * {@inheritDoc} */
public String resolve(TypeDescription instrumentedType) { return prefix; } } }
A value consumer that is responsible for adding a field value to the string creating StringBuilder.
/** * A value consumer that is responsible for adding a field value to the string creating {@link StringBuilder}. */
protected enum ValueConsumer implements StackManipulation {
A value consumer for a boolean value.
/** * A value consumer for a {@code boolean} value. */
BOOLEAN {
{@inheritDoc}
/** {@inheritDoc} */
public Size apply(MethodVisitor methodVisitor, Context implementationContext) { methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Z)Ljava/lang/StringBuilder;", false); return new Size(0, 0); } },
A value consumer for a char value.
/** * A value consumer for a {@code char} value. */
CHARACTER {
{@inheritDoc}
/** {@inheritDoc} */
public Size apply(MethodVisitor methodVisitor, Context implementationContext) { methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(C)Ljava/lang/StringBuilder;", false); return new Size(0, 0); } },
A value consumer for an int value.
/** * A value consumer for an {@code int} value. */
INTEGER {
{@inheritDoc}
/** {@inheritDoc} */
public Size apply(MethodVisitor methodVisitor, Context implementationContext) { methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(I)Ljava/lang/StringBuilder;", false); return new Size(0, 0); } },
A value consumer for a long value.
/** * A value consumer for a {@code long} value. */
LONG {
{@inheritDoc}
/** {@inheritDoc} */
public Size apply(MethodVisitor methodVisitor, Context implementationContext) { methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(J)Ljava/lang/StringBuilder;", false); return new Size(-1, 0); } },
A value consumer for a float value.
/** * A value consumer for a {@code float} value. */
FLOAT {
{@inheritDoc}
/** {@inheritDoc} */
public Size apply(MethodVisitor methodVisitor, Context implementationContext) { methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(F)Ljava/lang/StringBuilder;", false); return new Size(0, 0); } },
A value consumer for a double value.
/** * A value consumer for a {@code double} value. */
DOUBLE {
{@inheritDoc}
/** {@inheritDoc} */
public Size apply(MethodVisitor methodVisitor, Context implementationContext) { methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(D)Ljava/lang/StringBuilder;", false); return new Size(-1, 0); } },
A value consumer for a String value.
/** * A value consumer for a {@link String} value. */
STRING {
{@inheritDoc}
/** {@inheritDoc} */
public Size apply(MethodVisitor methodVisitor, Context implementationContext) { methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); return new Size(0, 0); } },
A value consumer for a CharSequence value.
/** * A value consumer for a {@link CharSequence} value. */
CHARACTER_SEQUENCE {
{@inheritDoc}
/** {@inheritDoc} */
public Size apply(MethodVisitor methodVisitor, Context implementationContext) { methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/CharSequence;)Ljava/lang/StringBuilder;", false); return new Size(0, 0); } },
A value consumer for a reference type.
/** * A value consumer for a reference type. */
OBJECT {
{@inheritDoc}
/** {@inheritDoc} */
public Size apply(MethodVisitor methodVisitor, Context implementationContext) { methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/Object;)Ljava/lang/StringBuilder;", false); return new Size(0, 0); } },
A value consumer for a boolean array type.
/** * A value consumer for a {@code boolean} array type. */
BOOLEAN_ARRAY {
{@inheritDoc}
/** {@inheritDoc} */
public Size apply(MethodVisitor methodVisitor, Context implementationContext) { methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/util/Arrays", "toString", "([Z)Ljava/lang/String;", false); methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); return new Size(0, 0); } },
A value consumer for a byte array type.
/** * A value consumer for a {@code byte} array type. */
BYTE_ARRAY {
{@inheritDoc}
/** {@inheritDoc} */
public Size apply(MethodVisitor methodVisitor, Context implementationContext) { methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/util/Arrays", "toString", "([B)Ljava/lang/String;", false); methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); return new Size(0, 0); } },
A value consumer for a short array type.
/** * A value consumer for a {@code short} array type. */
SHORT_ARRAY {
{@inheritDoc}
/** {@inheritDoc} */
public Size apply(MethodVisitor methodVisitor, Context implementationContext) { methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/util/Arrays", "toString", "([S)Ljava/lang/String;", false); methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); return new Size(0, 0); } },
A value consumer for a char array type.
/** * A value consumer for a {@code char} array type. */
CHARACTER_ARRAY {
{@inheritDoc}
/** {@inheritDoc} */
public Size apply(MethodVisitor methodVisitor, Context implementationContext) { methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/util/Arrays", "toString", "([C)Ljava/lang/String;", false); methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); return new Size(0, 0); } },
A value consumer for an int array type.
/** * A value consumer for an {@code int} array type. */
INTEGER_ARRAY {
{@inheritDoc}
/** {@inheritDoc} */
public Size apply(MethodVisitor methodVisitor, Context implementationContext) { methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/util/Arrays", "toString", "([I)Ljava/lang/String;", false); methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); return new Size(0, 0); } },
A value consumer for a long array type.
/** * A value consumer for a {@code long} array type. */
LONG_ARRAY {
{@inheritDoc}
/** {@inheritDoc} */
public Size apply(MethodVisitor methodVisitor, Context implementationContext) { methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/util/Arrays", "toString", "([J)Ljava/lang/String;", false); methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); return new Size(0, 0); } },
A value consumer for a float array type.
/** * A value consumer for a {@code float} array type. */
FLOAT_ARRAY {
{@inheritDoc}
/** {@inheritDoc} */
public Size apply(MethodVisitor methodVisitor, Context implementationContext) { methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/util/Arrays", "toString", "([F)Ljava/lang/String;", false); methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); return new Size(0, 0); } },
A value consumer for a double array type.
/** * A value consumer for a {@code double} array type. */
DOUBLE_ARRAY {
{@inheritDoc}
/** {@inheritDoc} */
public Size apply(MethodVisitor methodVisitor, Context implementationContext) { methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/util/Arrays", "toString", "([D)Ljava/lang/String;", false); methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); return new Size(0, 0); } },
A value consumer for a reference array type.
/** * A value consumer for a reference array type. */
REFERENCE_ARRAY {
{@inheritDoc}
/** {@inheritDoc} */
public Size apply(MethodVisitor methodVisitor, Context implementationContext) { methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/util/Arrays", "toString", "([Ljava/lang/Object;)Ljava/lang/String;", false); methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); return new Size(0, 0); } },
A value consumer for a nested array type.
/** * A value consumer for a nested array type. */
NESTED_ARRAY {
{@inheritDoc}
/** {@inheritDoc} */
public Size apply(MethodVisitor methodVisitor, Context implementationContext) { methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/util/Arrays", "deepToString", "([Ljava/lang/Object;)Ljava/lang/String;", false); methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); return new Size(0, 0); } };
Resolves an appropriate value resolver for a given type.
Params:
  • typeDescription – The type for which to resolve a value resolver.
Returns:An appropriate stack manipulation.
/** * Resolves an appropriate value resolver for a given type. * * @param typeDescription The type for which to resolve a value resolver. * @return An appropriate stack manipulation. */
protected static StackManipulation of(TypeDescription typeDescription) { if (typeDescription.represents(boolean.class)) { return BOOLEAN; } else if (typeDescription.represents(char.class)) { return CHARACTER; } else if (typeDescription.represents(byte.class) || typeDescription.represents(short.class) || 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 if (typeDescription.represents(String.class)) { return STRING; } else if (typeDescription.isAssignableTo(CharSequence.class)) { return CHARACTER_SEQUENCE; } else if (typeDescription.represents(boolean[].class)) { return BOOLEAN_ARRAY; } else if (typeDescription.represents(byte[].class)) { return BYTE_ARRAY; } else if (typeDescription.represents(short[].class)) { return SHORT_ARRAY; } else if (typeDescription.represents(char[].class)) { return CHARACTER_ARRAY; } else if (typeDescription.represents(int[].class)) { return INTEGER_ARRAY; } else if (typeDescription.represents(long[].class)) { return LONG_ARRAY; } else if (typeDescription.represents(float[].class)) { return FLOAT_ARRAY; } else if (typeDescription.represents(double[].class)) { return DOUBLE_ARRAY; } else if (typeDescription.isArray()) { return typeDescription.getComponentType().isArray() ? NESTED_ARRAY : REFERENCE_ARRAY; } else { return OBJECT; } }
{@inheritDoc}
/** * {@inheritDoc} */
public boolean isValid() { return true; } } }