1 // -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
4 // Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
5 // ---------------------------------------------------------------------------
6 // SquirrelJME is under the GNU General Public License v3+, or later.
7 // See license.mkd for licensing and copyright information.
8 // ---------------------------------------------------------------------------
10 package net
.multiphasicapps
.classfile
;
12 import cc
.squirreljme
.runtime
.cldc
.debug
.Debugging
;
13 import java
.io
.DataInputStream
;
14 import java
.io
.IOException
;
15 import java
.util
.LinkedHashMap
;
17 import net
.multiphasicapps
.collections
.UnmodifiableMap
;
20 * This represents an annotation which has values assigned to keys.
24 public final class Annotation
25 implements AnnotationValue
27 /** The type name of the annotation. */
28 protected final ClassName typename
;
30 /** The values for the annotation. */
31 private final Map
<MethodName
, AnnotationValue
> _values
=
32 new LinkedHashMap
<>();
35 * Initializes the annotation.
37 * @param __tn The type name to use.
38 * @param __vs The value mappings.
39 * @throws InvalidClassFormatException If an annotation key is duplicated.
40 * @throws NullPointerException On null arguments or if the value mappings
41 * contain a null value.
44 private Annotation(ClassName __tn
, Map
<MethodName
, AnnotationValue
> __vs
)
45 throws InvalidClassFormatException
, NullPointerException
47 if (__tn
== null || __vs
== null)
48 throw new NullPointerException("NARG");
52 // Copy key and values over
53 Map
<MethodName
, AnnotationValue
> values
= this._values
;
54 for (Map
.Entry
<MethodName
, AnnotationValue
> e
: __vs
.entrySet())
56 MethodName k
= e
.getKey();
57 AnnotationValue v
= e
.getValue();
59 if (k
== null || v
== null)
60 throw new NullPointerException();
62 // {@squirreljme.error JC1t Duplicate key within annotation. (The
64 if (null != values
.put(k
, v
))
65 throw new InvalidClassFormatException(String
.format(
75 public final boolean equals(Object __o
)
77 throw Debugging
.todo();
81 * Returns the value for the given method name.
83 * @param __n The key to get the value for.
84 * @return The value of the given key.
85 * @throws NullPointerException On null arguments.
88 public final AnnotationValue
get(MethodName __n
)
89 throws NullPointerException
91 // Will never be found
93 throw new NullPointerException("NARG");
95 throw Debugging
.todo();
103 public final int hashCode()
105 throw Debugging
.todo();
109 * Returns the key and value map.
111 * @return The key and value map.
114 public final Map
<MethodName
, AnnotationValue
> keyValueMap()
116 return UnmodifiableMap
.<MethodName
, AnnotationValue
>of(this._values
);
124 public final String
toString()
126 throw Debugging
.todo();
130 * Returns the type of this annotation.
132 * @return The annotation type.
135 public final ClassName
type()
137 return this.typename
;
141 * Decodes a single annotation from the input data stream and returns the
144 * @param __pool The constant pool.
145 * @param __in The input stream to read from.
146 * @return The parsed annotation.
147 * @throws InvalidClassFormatException If the annotation is invalid.
148 * @throws IOException On read errors.
149 * @throws NullPointerException On null arguments.
152 public static Annotation
parse(Pool __pool
, DataInputStream __in
)
153 throws InvalidClassFormatException
, IOException
, NullPointerException
155 if (__pool
== null || __in
== null)
156 throw new NullPointerException("NARG");
158 // Read the type name, which is a class
160 ClassName typename
= new FieldDescriptor((rawtypename
= __pool
.
161 <UTFConstantEntry
>get(UTFConstantEntry
.class,
162 __in
.readUnsignedShort()).toString())).className();
164 // {@squirreljme.error JC1u Annotation type is not correct. (The type)}
165 if (typename
== null)
166 throw new InvalidClassFormatException(String
.format("JC1u %s",
169 // Read element table
170 Map
<MethodName
, AnnotationValue
> values
= new LinkedHashMap
<>();
171 int n
= __in
.readUnsignedShort();
172 for (int i
= 0; i
< n
; i
++)
173 values
.put(new MethodName(__pool
.<UTFConstantEntry
>get(
174 UTFConstantEntry
.class, __in
.readUnsignedShort()).toString()),
175 Annotation
.parseValue(__pool
, __in
));
177 return new Annotation(typename
, values
);
181 * Parses a single annotation value.
183 * @param __pool The pool to read from.
184 * @param __in The input stream.
185 * @return The read value.
186 * @throws InvalidClassFormatException If the value is not valid.
187 * @throws IOException On read errors.
188 * @throws NullPointerException On null arguments.
191 public static AnnotationValue
parseValue(Pool __pool
,
192 DataInputStream __in
)
193 throws InvalidClassFormatException
, IOException
, NullPointerException
195 if (__pool
== null || __in
== null)
196 throw new NullPointerException("NARG");
198 // Read tag, which represents the type of things
199 int tag
= __in
.readUnsignedByte();
210 return new AnnotationValuePrimitive(
211 __pool
.<ConstantValueNumber
>get(ConstantValueNumber
.class,
212 __in
.readUnsignedShort()).number());
215 return new AnnotationValueString(
216 __pool
.<ConstantValueString
>get(ConstantValueString
.class,
217 __in
.readUnsignedShort()).toString());
220 return new AnnotationValueEnum(
221 new FieldDescriptor(__pool
.<UTFConstantEntry
>get(
222 UTFConstantEntry
.class, __in
.readUnsignedShort()).
224 new FieldName(__pool
.<UTFConstantEntry
>get(
225 UTFConstantEntry
.class, __in
.readUnsignedShort()).
229 return new AnnotationValueClass(new FieldDescriptor(
230 __pool
.<UTFConstantEntry
>get(UTFConstantEntry
.class,
231 __in
.readUnsignedShort()).toString()));
234 return Annotation
.parse(__pool
, __in
);
239 int len
= __in
.readUnsignedShort();
241 // Read in all values
242 AnnotationValue
[] values
= new AnnotationValue
[len
];
243 for (int i
= 0; i
< len
; i
++)
244 values
[i
] = Annotation
.parseValue(__pool
, __in
);
247 return new AnnotationValueArray(values
);
250 // {@squirreljme.error JC1v Invalid tag specified in
251 // annotation. (The tag used)}
253 throw new InvalidClassFormatException(
254 String
.format("JC1v %c", tag
));