modules/tool-classfile/src/main/java/net/multiphasicapps/classfile/Field.java
// -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
// ---------------------------------------------------------------------------
// SquirrelJME
// Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
// ---------------------------------------------------------------------------
// SquirrelJME is under the Mozilla Public License Version 2.0.
// See license.mkd for licensing and copyright information.
// ---------------------------------------------------------------------------
package net.multiphasicapps.classfile;
import java.io.DataInputStream;
import java.io.IOException;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.util.HashSet;
import java.util.Set;
/**
* This represents a field in a class which is used to store values either as
* static instances or as instance variables outside of methods.
*
* @since 2017/09/30
*/
public final class Field
extends Member
implements Annotated
{
/** The flags for the field. */
protected final FieldFlags flags;
/** The name of the field. */
protected final FieldName name;
/** The descriptor of the field. */
protected final FieldDescriptor type;
/** The constant value, if there is none then this is {@code null}. */
protected final ConstantValue constval;
/** Annotated values. */
protected final AnnotationTable annotations;
/** Name and type reference. */
private Reference<FieldNameAndType> _nameandtype;
/**
* Initializes the field.
*
* @param __f The flags for the field.
* @param __n The name of the field.
* @param __t The type of the field.
* @param __cv The constant value of the field, may be {@code null}.
* @param __avs Annotated values.
* @throws InvalidClassFormatException If the class format is not valid.
* @throws NullPointerException On null arguments, except for {@code __cv}.
* @since 2017/10/02
*/
public Field(FieldFlags __f, FieldName __n, FieldDescriptor __t,
ConstantValue __cv, AnnotationTable __avs)
throws InvalidClassFormatException, NullPointerException
{
if (__f == null || __n == null || __t == null)
throw new NullPointerException("NARG");
/* {@squirreljme.error JC2o The constant value is not compatible with
the given field type. (The value; The value type; The field type)} */
if (__cv != null && !__cv.type().isCompatibleWith(__t))
throw new InvalidClassFormatException(String.format(
"JC2o %s %s %s", __cv, __cv.type(), __t));
this.flags = __f;
this.name = __n;
this.type = __t;
this.constval = __cv;
this.annotations = (__avs == null ? new AnnotationTable() : __avs);
}
/**
* {@inheritDoc}
* @since 2018/03/06
*/
@Override
public final AnnotationTable annotationTable()
{
return this.annotations;
}
/**
* Returns the constant value of the field.
*
* @return The field constant value.
* @since 2018/05/14
*/
public final ConstantValue constantValue()
{
return this.constval;
}
/**
* {@inheritDoc}
* @since 2017/10/12
*/
@Override
public final FieldFlags flags()
{
return this.flags;
}
/**
* Returns the name of the field.
*
* @return The field name.
* @since 2018/05/14
*/
public final FieldName name()
{
return this.name;
}
/**
* {@inheritDoc}
* @since 2017/10/12
*/
@Override
public final FieldNameAndType nameAndType()
{
Reference<FieldNameAndType> ref = this._nameandtype;
FieldNameAndType rv;
if (ref == null || null == (rv = ref.get()))
this._nameandtype = new SoftReference<>(
rv = new FieldNameAndType(this.name, this.type));
return rv;
}
/**
* Returns the field type.
*
* @return The field type.
* @since 2018/05/14
*/
public final FieldDescriptor type()
{
return this.type;
}
/**
* Decodes all fields from the input class data.
*
* @param __ver The version of the class.
* @param __tn The name of the owning class.
* @param __cf The flags for the owning class.
* @param __pool The constant pool for the class.
* @throws InvalidClassFormatException If the class is not formatted
* correctly.
* @throws IOException On read errors.
* @throws NullPointerException On null arguments.
* @since 2017/09/30
*/
public static Field[] decode(ClassVersion __ver, ClassName __tn,
ClassFlags __cf, Pool __pool, DataInputStream __in)
throws InvalidClassFormatException, IOException, NullPointerException
{
if (__ver == null || __tn == null || __cf == null || __pool == null ||
__in == null)
throw new NullPointerException("NARG");
int nf = __in.readUnsignedShort();
Field[] rv = new Field[nf];
Set<NameAndType> dup = new HashSet<>();
// Parse fields
for (int i = 0; i < nf; i++)
{
FieldFlags flags = new FieldFlags(__cf, __in.readUnsignedShort());
FieldName name = new FieldName(
__pool.<UTFConstantEntry>require(UTFConstantEntry.class,
__in.readUnsignedShort()).toString());
FieldDescriptor type = new FieldDescriptor(
__pool.<UTFConstantEntry>require(UTFConstantEntry.class,
__in.readUnsignedShort()).toString());
/* {@squirreljme.error JC2p A duplicate method exists within the
class. (The method name; The method descriptor)} */
if (!dup.add(new NameAndType(name.toString(), type.toString())))
throw new InvalidClassFormatException(String.format(
"JC2p %s %s", name, type));
// Handle attributes
AttributeTable attrs = AttributeTable.parse(__pool, __in);
// Parse annotations
AnnotationTable annotations = AnnotationTable.parse(__pool, attrs);
// Parse constant value if there is one
ConstantValue constval = null;
Attribute cvalattr = attrs.get("ConstantValue");
if (cvalattr != null)
try (DataInputStream ai = cvalattr.open())
{
constval = __pool.<ConstantValue>require(
ConstantValue.class, ai.readUnsignedShort());
}
// Create field
rv[i] = new Field(flags, name, type, constval, annotations);
}
// All done!
return rv;
}
}