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

io.github.dmlloyd.classfile.AnnotationValue Maven / Gradle / Ivy

There is a newer version: 24.cr2
Show newest version
/*
 * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package io.github.dmlloyd.classfile;

import io.github.dmlloyd.classfile.constantpool.*;
import java.lang.constant.ClassDesc;
import java.lang.constant.Constable;
import java.util.ArrayList;
import java.util.List;

import io.github.dmlloyd.classfile.impl.AnnotationImpl;
import io.github.dmlloyd.classfile.impl.TemporaryConstantPool;
import io.github.dmlloyd.classfile.impl.Util;

import static java.util.Objects.requireNonNull;

/**
 * Models an {@code element_value} structure, or a value of an element-value
 * pair of an annotation, as defined in JVMS {@jvms 4.7.16.1}.
 * 

* Two {@code AnnotationValue} objects should be compared using the {@link * Object#equals(Object) equals} method. * * @see Annotation * @see AnnotationElement * * @sealedGraph * @since 24 */ public sealed interface AnnotationValue { /** * Models an annotation value of an element-value pair. * The {@linkplain #tag tag} of this value is {@value TAG_ANNOTATION}. * * @since 24 */ sealed interface OfAnnotation extends AnnotationValue permits AnnotationImpl.OfAnnotationImpl { /** {@return the annotation value} */ Annotation annotation(); } /** * Models an array value of an element-value pair. * The {@linkplain #tag tag} of this value is {@value TAG_ARRAY}. * * @since 24 */ sealed interface OfArray extends AnnotationValue permits AnnotationImpl.OfArrayImpl { /** * {@return the array elements of the array value} * * @apiNote * All array elements derived from Java source code have the same type, * which must not be an array type. (JLS {@jls 9.6.1}) If such elements are * annotations, they have the same annotation interface; if such elements * are enum, they belong to the same enum class. */ List values(); } /** * Models a constant value of an element-value pair. * * @sealedGraph * @since 24 */ sealed interface OfConstant extends AnnotationValue { /** * {@return the constant pool entry backing this constant element} * * @apiNote * Different types of constant values may share the same type of entry * because they have the same {@linkplain TypeKind##computational-type * computational type}. * For example, {@link OfInt} and {@link OfChar} are both * backed by {@link IntegerEntry}. Use {@link #resolvedValue * resolvedValue()} for a value of accurate type. */ AnnotationConstantValueEntry constant(); /** * {@return the resolved live constant value, as an object} The type of * the returned value may be a wrapper class or {@link String}. * * @apiNote * The returned object, despite being {@link Constable}, may not * {@linkplain Constable#describeConstable() describe} the right constant * for encoding the annotation value in a class file. For example, * {@link Character} returned by {@link OfChar} describes itself as a * {@link DynamicConstantPoolEntry}, but it is actually backed by * {@link IntegerEntry} in annotation format. * Use {@link #constant constant()} for a correct constant pool representation. */ Constable resolvedValue(); } /** * Models a string value of an element-value pair. * The {@linkplain #tag tag} of this value is {@value TAG_STRING}. * * @since 24 */ sealed interface OfString extends OfConstant permits AnnotationImpl.OfStringImpl { /** {@return the backing UTF8 entry} */ @Override Utf8Entry constant(); /** {@return the constant string value} */ String stringValue(); /** * {@return the resolved string value} * * @implSpec * This method returns the same as {@link #stringValue()}. */ @Override default String resolvedValue() { return stringValue(); } } /** * Models a double value of an element-value pair. * The {@linkplain #tag tag} of this value is {@value TAG_DOUBLE}. * * @since 24 */ sealed interface OfDouble extends OfConstant permits AnnotationImpl.OfDoubleImpl { /** {@return the backing double entry} */ @Override DoubleEntry constant(); /** {@return the constant double value} */ double doubleValue(); /** * {@return the resolved double value} * * @implSpec * This method returns the same as {@link #doubleValue()}. */ @Override default Double resolvedValue() { return doubleValue(); } } /** * Models a float value of an element-value pair. * The {@linkplain #tag tag} of this value is {@value TAG_FLOAT}. * * @since 24 */ sealed interface OfFloat extends OfConstant permits AnnotationImpl.OfFloatImpl { /** {@return the backing float entry} */ @Override FloatEntry constant(); /** {@return the constant float value} */ float floatValue(); /** * {@return the resolved float value} * * @implSpec * This method returns the same as {@link #floatValue()}. */ @Override default Float resolvedValue() { return floatValue(); } } /** * Models a long value of an element-value pair. * The {@linkplain #tag tag} of this value is {@value TAG_LONG}. * * @since 24 */ sealed interface OfLong extends OfConstant permits AnnotationImpl.OfLongImpl { /** {@return the backing long entry} */ @Override LongEntry constant(); /** {@return the constant long value} */ long longValue(); /** * {@return the resolved long value} * * @implSpec * This method returns the same as {@link #longValue()}. */ @Override default Long resolvedValue() { return longValue(); } } /** * Models an int value of an element-value pair. * The {@linkplain #tag tag} of this value is {@value TAG_INT}. * * @since 24 */ sealed interface OfInt extends OfConstant permits AnnotationImpl.OfIntImpl { /** {@return the backing integer entry} */ @Override IntegerEntry constant(); /** {@return the constant int value} */ int intValue(); /** * {@return the resolved int value} * * @implSpec * This method returns the same as {@link #intValue()}. */ @Override default Integer resolvedValue() { return intValue(); } } /** * Models a short value of an element-value pair. * The {@linkplain #tag tag} of this value is {@value TAG_SHORT}. * * @since 24 */ sealed interface OfShort extends OfConstant permits AnnotationImpl.OfShortImpl { /** {@return the backing integer entry} */ @Override IntegerEntry constant(); /** * {@return the constant short value} * @jvms 2.11.1 Types and the Java Virtual Machine */ short shortValue(); /** * {@return the resolved short value} * * @implSpec * This method returns the same as {@link #shortValue()}. */ @Override default Short resolvedValue() { return shortValue(); } } /** * Models a char value of an element-value pair. * The {@linkplain #tag tag} of this value is {@value TAG_CHAR}. * * @since 24 */ sealed interface OfChar extends OfConstant permits AnnotationImpl.OfCharImpl { /** {@return the backing integer entry} */ @Override IntegerEntry constant(); /** * {@return the constant char value} * @jvms 2.11.1 Types and the Java Virtual Machine */ char charValue(); /** * {@return the resolved char value} * * @implSpec * This method returns the same as {@link #charValue()}. */ @Override default Character resolvedValue() { return charValue(); } } /** * Models a byte value of an element-value pair. * The {@linkplain #tag tag} of this value is {@value TAG_BYTE}. * * @since 24 */ sealed interface OfByte extends OfConstant permits AnnotationImpl.OfByteImpl { /** {@return the backing integer entry} */ @Override IntegerEntry constant(); /** * {@return the constant byte value} * @jvms 2.11.1 Types and the Java Virtual Machine */ byte byteValue(); /** * {@return the resolved byte value} * * @implSpec * This method returns the same as {@link #byteValue()}. */ @Override default Byte resolvedValue() { return byteValue(); } } /** * Models a boolean value of an element-value pair. * The {@linkplain #tag tag} of this value is {@value TAG_BOOLEAN}. * * @since 24 */ sealed interface OfBoolean extends OfConstant permits AnnotationImpl.OfBooleanImpl { /** {@return the backing integer entry} */ @Override IntegerEntry constant(); /** * {@return the constant boolean value} * @jvms 2.3.4 The boolean Type */ boolean booleanValue(); /** * {@return the resolved boolean value} * * @implSpec * This method returns the same as {@link #booleanValue()}. */ @Override default Boolean resolvedValue() { return booleanValue(); } } /** * Models a class value of an element-value pair. * The {@linkplain #tag tag} of this value is {@value TAG_CLASS}. * * @since 24 */ sealed interface OfClass extends AnnotationValue permits AnnotationImpl.OfClassImpl { /** {@return the class descriptor string} */ Utf8Entry className(); /** {@return the class descriptor} */ default ClassDesc classSymbol() { return Util.fieldTypeSymbol(className()); } } /** * Models an enum value of an element-value pair. * The {@linkplain #tag tag} of this value is {@value TAG_ENUM}. * * @since 24 */ sealed interface OfEnum extends AnnotationValue permits AnnotationImpl.OfEnumImpl { /** {@return the enum class descriptor string} */ Utf8Entry className(); /** {@return the enum class descriptor} */ default ClassDesc classSymbol() { return Util.fieldTypeSymbol(className()); } /** {@return the enum constant name} */ Utf8Entry constantName(); } /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfByte}. */ int TAG_BYTE = 'B'; /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfChar}. */ int TAG_CHAR = 'C'; /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfDouble}. */ int TAG_DOUBLE = 'D'; /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfFloat}. */ int TAG_FLOAT = 'F'; /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfInt}. */ int TAG_INT = 'I'; /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfLong}. */ int TAG_LONG = 'J'; /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfShort}. */ int TAG_SHORT = 'S'; /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfBoolean}. */ int TAG_BOOLEAN = 'Z'; /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfString}. */ int TAG_STRING = 's'; /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfEnum}. */ int TAG_ENUM = 'e'; /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfClass}. */ int TAG_CLASS = 'c'; /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfAnnotation}. */ int TAG_ANNOTATION = '@'; /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfArray}. */ int TAG_ARRAY = '['; /** * {@return the tag character for this value as per JVMS {@jvms 4.7.16.1}} * The tag characters have a one-to-one mapping to the types of annotation element values. * * @apiNote * {@code TAG_}-prefixed constants in this class, such as {@link #TAG_INT}, * describe the possible return values of this method. */ char tag(); /** * {@return an enum value for an element-value pair} * @param className the descriptor string of the enum class * @param constantName the name of the enum constant */ static OfEnum ofEnum(Utf8Entry className, Utf8Entry constantName) { requireNonNull(className); requireNonNull(constantName); return new AnnotationImpl.OfEnumImpl(className, constantName); } /** * {@return an enum value for an element-value pair} * @param className the descriptor of the enum class * @param constantName the name of the enum constant */ static OfEnum ofEnum(ClassDesc className, String constantName) { return ofEnum(TemporaryConstantPool.INSTANCE.utf8Entry(className), TemporaryConstantPool.INSTANCE.utf8Entry(constantName)); } /** * {@return a class value for an element-value pair} * @param className the descriptor string of the class */ static OfClass ofClass(Utf8Entry className) { requireNonNull(className); return new AnnotationImpl.OfClassImpl(className); } /** * {@return a class value for an element-value pair} * @param className the descriptor of the class */ static OfClass ofClass(ClassDesc className) { return ofClass(TemporaryConstantPool.INSTANCE.utf8Entry(className)); } /** * {@return a string value for an element-value pair} * @param value the string */ static OfString ofString(Utf8Entry value) { requireNonNull(value); return new AnnotationImpl.OfStringImpl(value); } /** * {@return a string value for an element-value pair} * @param value the string */ static OfString ofString(String value) { return ofString(TemporaryConstantPool.INSTANCE.utf8Entry(value)); } /** * {@return a double value for an element-value pair} * @param value the double value */ static OfDouble ofDouble(DoubleEntry value) { requireNonNull(value); return new AnnotationImpl.OfDoubleImpl(value); } /** * {@return a double value for an element-value pair} * @param value the double value */ static OfDouble ofDouble(double value) { return ofDouble(TemporaryConstantPool.INSTANCE.doubleEntry(value)); } /** * {@return a float value for an element-value pair} * @param value the float value */ static OfFloat ofFloat(FloatEntry value) { requireNonNull(value); return new AnnotationImpl.OfFloatImpl(value); } /** * {@return a float value for an element-value pair} * @param value the float value */ static OfFloat ofFloat(float value) { return ofFloat(TemporaryConstantPool.INSTANCE.floatEntry(value)); } /** * {@return a long value for an element-value pair} * @param value the long value */ static OfLong ofLong(LongEntry value) { requireNonNull(value); return new AnnotationImpl.OfLongImpl(value); } /** * {@return a long value for an element-value pair} * @param value the long value */ static OfLong ofLong(long value) { return ofLong(TemporaryConstantPool.INSTANCE.longEntry(value)); } /** * {@return an int value for an element-value pair} * @param value the int value */ static OfInt ofInt(IntegerEntry value) { requireNonNull(value); return new AnnotationImpl.OfIntImpl(value); } /** * {@return an int value for an element-value pair} * @param value the int value */ static OfInt ofInt(int value) { return ofInt(TemporaryConstantPool.INSTANCE.intEntry(value)); } /** * {@return a short value for an element-value pair} * @param value the short value */ static OfShort ofShort(IntegerEntry value) { requireNonNull(value); return new AnnotationImpl.OfShortImpl(value); } /** * {@return a short value for an element-value pair} * @param value the short value */ static OfShort ofShort(short value) { return ofShort(TemporaryConstantPool.INSTANCE.intEntry(value)); } /** * {@return a char value for an element-value pair} * @param value the char value */ static OfChar ofChar(IntegerEntry value) { requireNonNull(value); return new AnnotationImpl.OfCharImpl(value); } /** * {@return a char value for an element-value pair} * @param value the char value */ static OfChar ofChar(char value) { return ofChar(TemporaryConstantPool.INSTANCE.intEntry(value)); } /** * {@return a byte value for an element-value pair} * @param value the byte value */ static OfByte ofByte(IntegerEntry value) { requireNonNull(value); return new AnnotationImpl.OfByteImpl(value); } /** * {@return a byte value for an element-value pair} * @param value the byte value */ static OfByte ofByte(byte value) { return ofByte(TemporaryConstantPool.INSTANCE.intEntry(value)); } /** * {@return a boolean value for an element-value pair} * @param value the boolean value */ static OfBoolean ofBoolean(IntegerEntry value) { requireNonNull(value); return new AnnotationImpl.OfBooleanImpl(value); } /** * {@return a boolean value for an element-value pair} * @param value the boolean value */ static OfBoolean ofBoolean(boolean value) { int i = value ? 1 : 0; return ofBoolean(TemporaryConstantPool.INSTANCE.intEntry(i)); } /** * {@return an annotation value for an element-value pair} * @param value the annotation */ static OfAnnotation ofAnnotation(Annotation value) { requireNonNull(value); return new AnnotationImpl.OfAnnotationImpl(value); } /** * {@return an array value for an element-value pair} * * @apiNote * See {@link AnnotationValue.OfArray#values() values()} for conventions * on array values derived from Java source code. * * @param values the array elements */ static OfArray ofArray(List values) { return new AnnotationImpl.OfArrayImpl(values); } /** * {@return an array value for an element-value pair} * * @apiNote * See {@link AnnotationValue.OfArray#values() values()} for conventions * on array values derived from Java source code. * * @param values the array elements */ static OfArray ofArray(AnnotationValue... values) { return ofArray(List.of(values)); } /** * {@return an annotation element} The {@code value} parameter must be * a primitive, a wrapper of primitive, a String, a ClassDesc, an enum * constant, or an array of one of these. * * @param value the annotation value * @throws IllegalArgumentException when the {@code value} parameter is not * a primitive, a wrapper of primitive, a String, a ClassDesc, * an enum constant, or an array of one of these. */ static AnnotationValue of(Object value) { if (value instanceof String s) { return ofString(s); } else if (value instanceof Byte b) { return ofByte(b); } else if (value instanceof Boolean b) { return ofBoolean(b); } else if (value instanceof Short s) { return ofShort(s); } else if (value instanceof Character c) { return ofChar(c); } else if (value instanceof Integer i) { return ofInt(i); } else if (value instanceof Long l) { return ofLong(l); } else if (value instanceof Float f) { return ofFloat(f); } else if (value instanceof Double d) { return ofDouble(d); } else if (value instanceof ClassDesc clsDesc) { return ofClass(clsDesc); } else if (value instanceof byte[] arr) { var els = new ArrayList(arr.length); for (var el : arr) { els.add(ofByte(el)); } return ofArray(els); } else if (value instanceof boolean[] arr) { var els = new ArrayList(arr.length); for (var el : arr) { els.add(ofBoolean(el)); } return ofArray(els); } else if (value instanceof short[] arr) { var els = new ArrayList(arr.length); for (var el : arr) { els.add(ofShort(el)); } return ofArray(els); } else if (value instanceof char[] arr) { var els = new ArrayList(arr.length); for (var el : arr) { els.add(ofChar(el)); } return ofArray(els); } else if (value instanceof int[] arr) { var els = new ArrayList(arr.length); for (var el : arr) { els.add(ofInt(el)); } return ofArray(els); } else if (value instanceof long[] arr) { var els = new ArrayList(arr.length); for (var el : arr) { els.add(ofLong(el)); } return ofArray(els); } else if (value instanceof float[] arr) { var els = new ArrayList(arr.length); for (var el : arr) { els.add(ofFloat(el)); } return ofArray(els); } else if (value instanceof double[] arr) { var els = new ArrayList(arr.length); for (var el : arr) { els.add(ofDouble(el)); } return ofArray(els); } else if (value instanceof Object[] arr) { var els = new ArrayList(arr.length); for (var el : arr) { els.add(of(el)); } return ofArray(els); } else if (value instanceof Enum e) { return ofEnum(ClassDesc.ofDescriptor(e.getDeclaringClass().descriptorString()), e.name()); } throw new IllegalArgumentException("Illegal annotation constant value type " + requireNonNull(value).getClass()); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy