/*
* Javassist, a Java-bytecode translator toolkit.
* Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. Alternatively, the contents of this file may be used under
* the terms of the GNU Lesser General Public License Version 2.1 or later,
* or the Apache License Version 2.0.
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*/
package javassist;
import java.util.List;
import javassist.bytecode.AccessFlag;
import javassist.bytecode.AnnotationsAttribute;
import javassist.bytecode.AttributeInfo;
import javassist.bytecode.Bytecode;
import javassist.bytecode.ClassFile;
import javassist.bytecode.ConstPool;
import javassist.bytecode.Descriptor;
import javassist.bytecode.FieldInfo;
import javassist.bytecode.SignatureAttribute;
import javassist.compiler.CompileError;
import javassist.compiler.Javac;
import javassist.compiler.SymbolTable;
import javassist.compiler.ast.ASTree;
import javassist.compiler.ast.DoubleConst;
import javassist.compiler.ast.IntConst;
import javassist.compiler.ast.StringL;
An instance of CtField represents a field.
See Also: - getDeclaredFields.getDeclaredFields()
/**
* An instance of CtField represents a field.
*
* @see CtClass#getDeclaredFields()
*/
public class CtField extends CtMember {
static final String javaLangString = "java.lang.String";
protected FieldInfo fieldInfo;
Creates a CtField
object.
The created field must be added to a class
with CtClass.addField()
.
An initial value of the field is specified
by a CtField.Initializer
object.
If getter and setter methods are needed,
call CtNewMethod.getter()
and
CtNewMethod.setter()
.
Params: - type – field type
- name – field name
- declaring – the class to which the field will be added.
See Also:
/**
* Creates a <code>CtField</code> object.
* The created field must be added to a class
* with <code>CtClass.addField()</code>.
* An initial value of the field is specified
* by a <code>CtField.Initializer</code> object.
*
* <p>If getter and setter methods are needed,
* call <code>CtNewMethod.getter()</code> and
* <code>CtNewMethod.setter()</code>.
*
* @param type field type
* @param name field name
* @param declaring the class to which the field will be added.
*
* @see CtClass#addField(CtField)
* @see CtNewMethod#getter(String,CtField)
* @see CtNewMethod#setter(String,CtField)
* @see CtField.Initializer
*/
public CtField(CtClass type, String name, CtClass declaring)
throws CannotCompileException
{
this(Descriptor.of(type), name, declaring);
}
Creates a copy of the given field.
The created field must be added to a class
with CtClass.addField()
.
An initial value of the field is specified
by a CtField.Initializer
object.
If getter and setter methods are needed,
call CtNewMethod.getter()
and
CtNewMethod.setter()
.
Params: - src – the original field
- declaring – the class to which the field will be added.
See Also:
/**
* Creates a copy of the given field.
* The created field must be added to a class
* with <code>CtClass.addField()</code>.
* An initial value of the field is specified
* by a <code>CtField.Initializer</code> object.
*
* <p>If getter and setter methods are needed,
* call <code>CtNewMethod.getter()</code> and
* <code>CtNewMethod.setter()</code>.
*
* @param src the original field
* @param declaring the class to which the field will be added.
* @see CtNewMethod#getter(String,CtField)
* @see CtNewMethod#setter(String,CtField)
* @see CtField.Initializer
*/
public CtField(CtField src, CtClass declaring)
throws CannotCompileException
{
this(src.fieldInfo.getDescriptor(), src.fieldInfo.getName(),
declaring);
FieldInfo fi = fieldInfo;
fi.setAccessFlags(src.fieldInfo.getAccessFlags());
ConstPool cp = fi.getConstPool();
List<AttributeInfo> attributes = src.fieldInfo.getAttributes();
for (AttributeInfo ainfo : attributes)
fi.addAttribute(ainfo.copy(cp, null));
}
private CtField(String typeDesc, String name, CtClass clazz)
throws CannotCompileException
{
super(clazz);
ClassFile cf = clazz.getClassFile2();
if (cf == null)
throw new CannotCompileException("bad declaring class: "
+ clazz.getName());
fieldInfo = new FieldInfo(cf.getConstPool(), name, typeDesc);
}
CtField(FieldInfo fi, CtClass clazz) {
super(clazz);
fieldInfo = fi;
}
Returns a String representation of the object.
/**
* Returns a String representation of the object.
*/
@Override
public String toString() {
return getDeclaringClass().getName() + "." + getName()
+ ":" + fieldInfo.getDescriptor();
}
@Override
protected void extendToString(StringBuffer buffer) {
buffer.append(' ');
buffer.append(getName());
buffer.append(' ');
buffer.append(fieldInfo.getDescriptor());
}
/* Javac.CtFieldWithInit overrides. */
protected ASTree getInitAST() { return null; }
/* Called by CtClassType.addField(). */
Initializer getInit() {
ASTree tree = getInitAST();
if (tree == null)
return null;
return Initializer.byExpr(tree);
}
Compiles the given source code and creates a field.
Examples of the source code are:
"public String name;"
"public int k = 3;"
Note that the source code ends with ';'
(semicolon).
Params: - src – the source text.
- declaring – the class to which the created field is added.
/**
* Compiles the given source code and creates a field.
* Examples of the source code are:
*
* <pre>
* "public String name;"
* "public int k = 3;"</pre>
*
* <p>Note that the source code ends with <code>';'</code>
* (semicolon).
*
* @param src the source text.
* @param declaring the class to which the created field is added.
*/
public static CtField make(String src, CtClass declaring)
throws CannotCompileException
{
Javac compiler = new Javac(declaring);
try {
CtMember obj = compiler.compile(src);
if (obj instanceof CtField)
return (CtField)obj; // an instance of Javac.CtFieldWithInit
}
catch (CompileError e) {
throw new CannotCompileException(e);
}
throw new CannotCompileException("not a field");
}
Returns the FieldInfo representing the field in the class file.
/**
* Returns the FieldInfo representing the field in the class file.
*/
public FieldInfo getFieldInfo() {
declaringClass.checkModify();
return fieldInfo;
}
Returns the FieldInfo representing the field in the class
file (read only).
Normal applications do not need calling this method. Use
getFieldInfo()
.
The FieldInfo
object obtained by this method
is read only. Changes to this object might not be reflected
on a class file generated by toBytecode()
,
toClass()
, etc in CtClass
.
This method is available even if the CtClass
containing this field is frozen. However, if the class is
frozen, the FieldInfo
might be also pruned.
See Also: - getFieldInfo()
- CtClass.isFrozen()
- CtClass.prune()
/**
* Returns the FieldInfo representing the field in the class
* file (read only).
* Normal applications do not need calling this method. Use
* <code>getFieldInfo()</code>.
*
* <p>The <code>FieldInfo</code> object obtained by this method
* is read only. Changes to this object might not be reflected
* on a class file generated by <code>toBytecode()</code>,
* <code>toClass()</code>, etc in <code>CtClass</code>.
*
* <p>This method is available even if the <code>CtClass</code>
* containing this field is frozen. However, if the class is
* frozen, the <code>FieldInfo</code> might be also pruned.
*
* @see #getFieldInfo()
* @see CtClass#isFrozen()
* @see CtClass#prune()
*/
public FieldInfo getFieldInfo2() { return fieldInfo; }
Returns the class declaring the field.
/**
* Returns the class declaring the field.
*/
@Override
public CtClass getDeclaringClass() {
// this is redundant but for javadoc.
return super.getDeclaringClass();
}
Returns the name of the field.
/**
* Returns the name of the field.
*/
@Override
public String getName() {
return fieldInfo.getName();
}
Changes the name of the field.
/**
* Changes the name of the field.
*/
public void setName(String newName) {
declaringClass.checkModify();
fieldInfo.setName(newName);
}
Returns the encoded modifiers of the field.
See Also: - Modifier
/**
* Returns the encoded modifiers of the field.
*
* @see Modifier
*/
@Override
public int getModifiers() {
return AccessFlag.toModifier(fieldInfo.getAccessFlags());
}
Sets the encoded modifiers of the field.
See Also: - Modifier
/**
* Sets the encoded modifiers of the field.
*
* @see Modifier
*/
@Override
public void setModifiers(int mod) {
declaringClass.checkModify();
fieldInfo.setAccessFlags(AccessFlag.of(mod));
}
Returns true if the class has the specified annotation type.
Params: - typeName – the name of annotation type.
Returns: true
if the annotation is found, otherwise false
.Since: 3.21
/**
* Returns true if the class has the specified annotation type.
*
* @param typeName the name of annotation type.
* @return <code>true</code> if the annotation is found, otherwise <code>false</code>.
* @since 3.21
*/
@Override
public boolean hasAnnotation(String typeName) {
FieldInfo fi = getFieldInfo2();
AnnotationsAttribute ainfo = (AnnotationsAttribute)
fi.getAttribute(AnnotationsAttribute.invisibleTag);
AnnotationsAttribute ainfo2 = (AnnotationsAttribute)
fi.getAttribute(AnnotationsAttribute.visibleTag);
return CtClassType.hasAnnotationType(typeName, getDeclaringClass().getClassPool(),
ainfo, ainfo2);
}
Returns the annotation if the class has the specified annotation class.
For example, if an annotation @Author
is associated
with this field, an Author
object is returned.
The member values can be obtained by calling methods on
the Author
object.
Params: - clz – the annotation class.
Returns: the annotation if found, otherwise null
. Since: 3.11
/**
* Returns the annotation if the class has the specified annotation class.
* For example, if an annotation <code>@Author</code> is associated
* with this field, an <code>Author</code> object is returned.
* The member values can be obtained by calling methods on
* the <code>Author</code> object.
*
* @param clz the annotation class.
* @return the annotation if found, otherwise <code>null</code>.
* @since 3.11
*/
@Override
public Object getAnnotation(Class<?> clz) throws ClassNotFoundException {
FieldInfo fi = getFieldInfo2();
AnnotationsAttribute ainfo = (AnnotationsAttribute)
fi.getAttribute(AnnotationsAttribute.invisibleTag);
AnnotationsAttribute ainfo2 = (AnnotationsAttribute)
fi.getAttribute(AnnotationsAttribute.visibleTag);
return CtClassType.getAnnotationType(clz, getDeclaringClass().getClassPool(),
ainfo, ainfo2);
}
Returns the annotations associated with this field.
See Also: Returns: an array of annotation-type objects. Since: 3.1
/**
* Returns the annotations associated with this field.
*
* @return an array of annotation-type objects.
* @see #getAvailableAnnotations()
* @since 3.1
*/
@Override
public Object[] getAnnotations() throws ClassNotFoundException {
return getAnnotations(false);
}
Returns the annotations associated with this field.
If any annotations are not on the classpath, they are not included
in the returned array.
See Also: Returns: an array of annotation-type objects. Since: 3.3
/**
* Returns the annotations associated with this field.
* If any annotations are not on the classpath, they are not included
* in the returned array.
*
* @return an array of annotation-type objects.
* @see #getAnnotations()
* @since 3.3
*/
@Override
public Object[] getAvailableAnnotations(){
try {
return getAnnotations(true);
}
catch (ClassNotFoundException e) {
throw new RuntimeException("Unexpected exception", e);
}
}
private Object[] getAnnotations(boolean ignoreNotFound) throws ClassNotFoundException {
FieldInfo fi = getFieldInfo2();
AnnotationsAttribute ainfo = (AnnotationsAttribute)
fi.getAttribute(AnnotationsAttribute.invisibleTag);
AnnotationsAttribute ainfo2 = (AnnotationsAttribute)
fi.getAttribute(AnnotationsAttribute.visibleTag);
return CtClassType.toAnnotationType(ignoreNotFound, getDeclaringClass().getClassPool(),
ainfo, ainfo2);
}
Returns the character string representing the type of the field.
The field signature is represented by a character string
called a field descriptor, which is defined in the JVM specification.
If two fields have the same type,
getSignature()
returns the same string.
Note that the returned string is not the type signature
contained in the SignatureAttirbute
. It is
a descriptor.
See Also: - Descriptor
- getGenericSignature()
/**
* Returns the character string representing the type of the field.
* The field signature is represented by a character string
* called a field descriptor, which is defined in the JVM specification.
* If two fields have the same type,
* <code>getSignature()</code> returns the same string.
*
* <p>Note that the returned string is not the type signature
* contained in the <code>SignatureAttirbute</code>. It is
* a descriptor.
*
* @see javassist.bytecode.Descriptor
* @see #getGenericSignature()
*/
@Override
public String getSignature() {
return fieldInfo.getDescriptor();
}
Returns the generic signature of the field.
It represents a type including type variables.
See Also: - toFieldSignature.toFieldSignature(String)
Since: 3.17
/**
* Returns the generic signature of the field.
* It represents a type including type variables.
*
* @see SignatureAttribute#toFieldSignature(String)
* @since 3.17
*/
@Override
public String getGenericSignature() {
SignatureAttribute sa
= (SignatureAttribute)fieldInfo.getAttribute(SignatureAttribute.tag);
return sa == null ? null : sa.getSignature();
}
Set the generic signature of the field. It represents a type including type variables. See CtClass.setGenericSignature(String)
for a code sample. Params: - sig – a new generic signature.
See Also: Since: 3.17
/**
* Set the generic signature of the field.
* It represents a type including type variables.
* See {@link javassist.CtClass#setGenericSignature(String)}
* for a code sample.
*
* @param sig a new generic signature.
* @see javassist.bytecode.SignatureAttribute.ObjectType#encode()
* @since 3.17
*/
@Override
public void setGenericSignature(String sig) {
declaringClass.checkModify();
fieldInfo.addAttribute(new SignatureAttribute(fieldInfo.getConstPool(), sig));
}
Returns the type of the field.
/**
* Returns the type of the field.
*/
public CtClass getType() throws NotFoundException {
return Descriptor.toCtClass(fieldInfo.getDescriptor(),
declaringClass.getClassPool());
}
Sets the type of the field.
This method does not automatically update method bodies that access this field. They have to be explicitly updated. For example, if some method contains an expression t.value
and the type of the variable t
is changed by setType(CtClass)
from int
to double
, then t.value
has to be modified as well since the bytecode of t.value
contains the type information.
See Also:
/**
* Sets the type of the field.
*
* <p>This method does not automatically update method bodies that access
* this field. They have to be explicitly updated. For example,
* if some method contains an expression {@code t.value} and the type
* of the variable {@code t} is changed by {@link #setType(CtClass)}
* from {@code int} to {@code double}, then {@code t.value} has to be modified
* as well since the bytecode of {@code t.value} contains the type information.
* </p>
*
* @see CodeConverter
* @see javassist.expr.ExprEditor
*/
public void setType(CtClass clazz) {
declaringClass.checkModify();
fieldInfo.setDescriptor(Descriptor.of(clazz));
}
Returns the value of this field if it is a constant field.
This method works only if the field type is a primitive type
or String
type. Otherwise, it returns null
.
A constant field is static
and final
.
Returns: a Integer
, Long
, Float
,
Double
, Boolean
,
or String
object
representing the constant value.
null
if it is not a constant field
or if the field type is not a primitive type
or String
.
/**
* Returns the value of this field if it is a constant field.
* This method works only if the field type is a primitive type
* or <code>String</code> type. Otherwise, it returns <code>null</code>.
* A constant field is <code>static</code> and <code>final</code>.
*
* @return a <code>Integer</code>, <code>Long</code>, <code>Float</code>,
* <code>Double</code>, <code>Boolean</code>,
* or <code>String</code> object
* representing the constant value.
* <code>null</code> if it is not a constant field
* or if the field type is not a primitive type
* or <code>String</code>.
*/
public Object getConstantValue() {
// When this method is modified,
// see also getConstantFieldValue() in TypeChecker.
int index = fieldInfo.getConstantValue();
if (index == 0)
return null;
ConstPool cp = fieldInfo.getConstPool();
switch (cp.getTag(index)) {
case ConstPool.CONST_Long :
return Long.valueOf(cp.getLongInfo(index));
case ConstPool.CONST_Float :
return Float.valueOf(cp.getFloatInfo(index));
case ConstPool.CONST_Double :
return Double.valueOf(cp.getDoubleInfo(index));
case ConstPool.CONST_Integer :
int value = cp.getIntegerInfo(index);
// "Z" means boolean type.
if ("Z".equals(fieldInfo.getDescriptor()))
return Boolean.valueOf(value != 0);
return Integer.valueOf(value);
case ConstPool.CONST_String :
return cp.getStringInfo(index);
default :
throw new RuntimeException("bad tag: " + cp.getTag(index)
+ " at " + index);
}
}
Obtains an attribute with the given name.
If that attribute is not found in the class file, this
method returns null.
Note that an attribute is a data block specified by the class file format. See AttributeInfo
.
Params: - name – attribute name
/**
* Obtains an attribute with the given name.
* If that attribute is not found in the class file, this
* method returns null.
*
* <p>Note that an attribute is a data block specified by
* the class file format.
* See {@link javassist.bytecode.AttributeInfo}.
*
* @param name attribute name
*/
@Override
public byte[] getAttribute(String name) {
AttributeInfo ai = fieldInfo.getAttribute(name);
if (ai == null)
return null;
return ai.get();
}
Adds an attribute. The attribute is saved in the class file.
Note that an attribute is a data block specified by the class file format. See AttributeInfo
.
Params: - name – attribute name
- data – attribute value
/**
* Adds an attribute. The attribute is saved in the class file.
*
* <p>Note that an attribute is a data block specified by
* the class file format.
* See {@link javassist.bytecode.AttributeInfo}.
*
* @param name attribute name
* @param data attribute value
*/
@Override
public void setAttribute(String name, byte[] data) {
declaringClass.checkModify();
fieldInfo.addAttribute(new AttributeInfo(fieldInfo.getConstPool(),
name, data));
}
// inner classes
Instances of this class specify how to initialize a field.
Initializer
is passed to
CtClass.addField()
with a CtField
.
This class cannot be instantiated with the new
operator.
Factory methods such as byParameter()
and
byNew
must be used for the instantiation. They create a new instance with
the given parameters and return it.
See Also: - addField.addField(CtField, Initializer)
/**
* Instances of this class specify how to initialize a field.
* <code>Initializer</code> is passed to
* <code>CtClass.addField()</code> with a <code>CtField</code>.
*
* <p>This class cannot be instantiated with the <code>new</code> operator.
* Factory methods such as <code>byParameter()</code> and
* <code>byNew</code>
* must be used for the instantiation. They create a new instance with
* the given parameters and return it.
*
* @see CtClass#addField(CtField,CtField.Initializer)
*/
public static abstract class Initializer {
Makes an initializer that assigns a constant integer value.
The field must be integer, short, char, or byte type.
/**
* Makes an initializer that assigns a constant integer value.
* The field must be integer, short, char, or byte type.
*/
public static Initializer constant(int i) {
return new IntInitializer(i);
}
Makes an initializer that assigns a constant boolean value.
The field must be boolean type.
/**
* Makes an initializer that assigns a constant boolean value.
* The field must be boolean type.
*/
public static Initializer constant(boolean b) {
return new IntInitializer(b ? 1 : 0);
}
Makes an initializer that assigns a constant long value.
The field must be long type.
/**
* Makes an initializer that assigns a constant long value.
* The field must be long type.
*/
public static Initializer constant(long l) {
return new LongInitializer(l);
}
Makes an initializer that assigns a constant float value.
The field must be float type.
/**
* Makes an initializer that assigns a constant float value.
* The field must be float type.
*/
public static Initializer constant(float l) {
return new FloatInitializer(l);
}
Makes an initializer that assigns a constant double value.
The field must be double type.
/**
* Makes an initializer that assigns a constant double value.
* The field must be double type.
*/
public static Initializer constant(double d) {
return new DoubleInitializer(d);
}
Makes an initializer that assigns a constant string value.
The field must be java.lang.String
type.
/**
* Makes an initializer that assigns a constant string value.
* The field must be <code>java.lang.String</code> type.
*/
public static Initializer constant(String s) {
return new StringInitializer(s);
}
Makes an initializer using a constructor parameter.
The initial value is the
N-th parameter given to the constructor of the object including
the field. If the constructor takes less than N parameters,
the field is not initialized.
If the field is static, it is never initialized.
Params: - nth – the n-th (>= 0) parameter is used as
the initial value.
If nth is 0, then the first parameter is
used.
/**
* Makes an initializer using a constructor parameter.
*
* <p>The initial value is the
* N-th parameter given to the constructor of the object including
* the field. If the constructor takes less than N parameters,
* the field is not initialized.
* If the field is static, it is never initialized.
*
* @param nth the n-th (>= 0) parameter is used as
* the initial value.
* If nth is 0, then the first parameter is
* used.
*/
public static Initializer byParameter(int nth) {
ParamInitializer i = new ParamInitializer();
i.nthParam = nth;
return i;
}
Makes an initializer creating a new object.
This initializer creates a new object and uses it as the initial
value of the field. The constructor of the created object receives
the parameter:
Object obj
- the object including the field.
If the initialized field is static, then the constructor does
not receive any parameters.
Params: - objectType – the class instantiated for the initial value.
/**
* Makes an initializer creating a new object.
*
* <p>This initializer creates a new object and uses it as the initial
* value of the field. The constructor of the created object receives
* the parameter:
*
* <p><code>Object obj</code> - the object including the field.
*
* <p>If the initialized field is static, then the constructor does
* not receive any parameters.
*
* @param objectType the class instantiated for the initial value.
*/
public static Initializer byNew(CtClass objectType) {
NewInitializer i = new NewInitializer();
i.objectType = objectType;
i.stringParams = null;
i.withConstructorParams = false;
return i;
}
Makes an initializer creating a new object.
This initializer creates a new object and uses it as the initial
value of the field. The constructor of the created object receives
the parameters:
Object obj
- the object including the field.
String[] strs
- the character strings specified
by stringParams
If the initialized field is static, then the constructor
receives only strs
.
Params: - objectType – the class instantiated for the initial value.
- stringParams – the array of strings passed to the
constructor.
/**
* Makes an initializer creating a new object.
*
* <p>This initializer creates a new object and uses it as the initial
* value of the field. The constructor of the created object receives
* the parameters:
*
* <p><code>Object obj</code> - the object including the field.<br>
* <code>String[] strs</code> - the character strings specified
* by <code>stringParams</code><br>
*
* <p>If the initialized field is static, then the constructor
* receives only <code>strs</code>.
*
* @param objectType the class instantiated for the initial value.
* @param stringParams the array of strings passed to the
* constructor.
*/
public static Initializer byNew(CtClass objectType,
String[] stringParams) {
NewInitializer i = new NewInitializer();
i.objectType = objectType;
i.stringParams = stringParams;
i.withConstructorParams = false;
return i;
}
Makes an initializer creating a new object.
This initializer creates a new object and uses it as the initial
value of the field. The constructor of the created object receives
the parameters:
Object obj
- the object including the field.
Object[] args
- the parameters passed to the
constructor of the object including the
filed.
If the initialized field is static, then the constructor does
not receive any parameters.
Params: - objectType – the class instantiated for the initial value.
See Also:
/**
* Makes an initializer creating a new object.
*
* <p>This initializer creates a new object and uses it as the initial
* value of the field. The constructor of the created object receives
* the parameters:
*
* <p><code>Object obj</code> - the object including the field.<br>
* <code>Object[] args</code> - the parameters passed to the
* constructor of the object including the
* filed.
*
* <p>If the initialized field is static, then the constructor does
* not receive any parameters.
*
* @param objectType the class instantiated for the initial value.
*
* @see javassist.CtField.Initializer#byNewArray(CtClass,int)
* @see javassist.CtField.Initializer#byNewArray(CtClass,int[])
*/
public static Initializer byNewWithParams(CtClass objectType) {
NewInitializer i = new NewInitializer();
i.objectType = objectType;
i.stringParams = null;
i.withConstructorParams = true;
return i;
}
Makes an initializer creating a new object.
This initializer creates a new object and uses it as the initial
value of the field. The constructor of the created object receives
the parameters:
Object obj
- the object including the field.
String[] strs
- the character strings specified
by stringParams
Object[] args
- the parameters passed to the
constructor of the object including the
filed.
If the initialized field is static, then the constructor receives
only strs
.
Params: - objectType – the class instantiated for the initial value.
- stringParams – the array of strings passed to the
constructor.
/**
* Makes an initializer creating a new object.
*
* <p>This initializer creates a new object and uses it as the initial
* value of the field. The constructor of the created object receives
* the parameters:
*
* <p><code>Object obj</code> - the object including the field.<br>
* <code>String[] strs</code> - the character strings specified
* by <code>stringParams</code><br>
* <code>Object[] args</code> - the parameters passed to the
* constructor of the object including the
* filed.
*
* <p>If the initialized field is static, then the constructor receives
* only <code>strs</code>.
*
* @param objectType the class instantiated for the initial value.
* @param stringParams the array of strings passed to the
* constructor.
*/
public static Initializer byNewWithParams(CtClass objectType,
String[] stringParams) {
NewInitializer i = new NewInitializer();
i.objectType = objectType;
i.stringParams = stringParams;
i.withConstructorParams = true;
return i;
}
Makes an initializer calling a static method.
This initializer calls a static method and uses the returned
value as the initial value of the field.
The called method receives the parameters:
Object obj
- the object including the field.
If the initialized field is static, then the method does
not receive any parameters.
The type of the returned value must be the same as the field
type.
Params: - methodClass – the class that the static method is
declared in.
- methodName – the name of the satic method.
/**
* Makes an initializer calling a static method.
*
* <p>This initializer calls a static method and uses the returned
* value as the initial value of the field.
* The called method receives the parameters:
*
* <p><code>Object obj</code> - the object including the field.
*
* <p>If the initialized field is static, then the method does
* not receive any parameters.
*
* <p>The type of the returned value must be the same as the field
* type.
*
* @param methodClass the class that the static method is
* declared in.
* @param methodName the name of the satic method.
*/
public static Initializer byCall(CtClass methodClass,
String methodName) {
MethodInitializer i = new MethodInitializer();
i.objectType = methodClass;
i.methodName = methodName;
i.stringParams = null;
i.withConstructorParams = false;
return i;
}
Makes an initializer calling a static method.
This initializer calls a static method and uses the returned
value as the initial value of the field. The called method
receives the parameters:
Object obj
- the object including the field.
String[] strs
- the character strings specified
by stringParams
If the initialized field is static, then the method
receive only strs
.
The type of the returned value must be the same as the field
type.
Params: - methodClass – the class that the static method is
declared in.
- methodName – the name of the satic method.
- stringParams – the array of strings passed to the
static method.
/**
* Makes an initializer calling a static method.
*
* <p>This initializer calls a static method and uses the returned
* value as the initial value of the field. The called method
* receives the parameters:
*
* <p><code>Object obj</code> - the object including the field.<br>
* <code>String[] strs</code> - the character strings specified
* by <code>stringParams</code><br>
*
* <p>If the initialized field is static, then the method
* receive only <code>strs</code>.
*
* <p>The type of the returned value must be the same as the field
* type.
*
* @param methodClass the class that the static method is
* declared in.
* @param methodName the name of the satic method.
* @param stringParams the array of strings passed to the
* static method.
*/
public static Initializer byCall(CtClass methodClass,
String methodName,
String[] stringParams) {
MethodInitializer i = new MethodInitializer();
i.objectType = methodClass;
i.methodName = methodName;
i.stringParams = stringParams;
i.withConstructorParams = false;
return i;
}
Makes an initializer calling a static method.
This initializer calls a static method and uses the returned
value as the initial value of the field. The called method
receives the parameters:
Object obj
- the object including the field.
Object[] args
- the parameters passed to the
constructor of the object including the
filed.
If the initialized field is static, then the method does
not receive any parameters.
The type of the returned value must be the same as the field
type.
Params: - methodClass – the class that the static method is
declared in.
- methodName – the name of the satic method.
/**
* Makes an initializer calling a static method.
*
* <p>This initializer calls a static method and uses the returned
* value as the initial value of the field. The called method
* receives the parameters:
*
* <p><code>Object obj</code> - the object including the field.<br>
* <code>Object[] args</code> - the parameters passed to the
* constructor of the object including the
* filed.
*
* <p>If the initialized field is static, then the method does
* not receive any parameters.
*
* <p>The type of the returned value must be the same as the field
* type.
*
* @param methodClass the class that the static method is
* declared in.
* @param methodName the name of the satic method.
*/
public static Initializer byCallWithParams(CtClass methodClass,
String methodName) {
MethodInitializer i = new MethodInitializer();
i.objectType = methodClass;
i.methodName = methodName;
i.stringParams = null;
i.withConstructorParams = true;
return i;
}
Makes an initializer calling a static method.
This initializer calls a static method and uses the returned
value as the initial value of the field. The called method
receives the parameters:
Object obj
- the object including the field.
String[] strs
- the character strings specified
by stringParams
Object[] args
- the parameters passed to the
constructor of the object including the
filed.
If the initialized field is static, then the method
receive only strs
.
The type of the returned value must be the same as the field
type.
Params: - methodClass – the class that the static method is
declared in.
- methodName – the name of the satic method.
- stringParams – the array of strings passed to the
static method.
/**
* Makes an initializer calling a static method.
*
* <p>This initializer calls a static method and uses the returned
* value as the initial value of the field. The called method
* receives the parameters:
*
* <p><code>Object obj</code> - the object including the field.<br>
* <code>String[] strs</code> - the character strings specified
* by <code>stringParams</code><br>
* <code>Object[] args</code> - the parameters passed to the
* constructor of the object including the
* filed.
*
* <p>If the initialized field is static, then the method
* receive only <code>strs</code>.
*
* <p>The type of the returned value must be the same as the field
* type.
*
* @param methodClass the class that the static method is
* declared in.
* @param methodName the name of the satic method.
* @param stringParams the array of strings passed to the
* static method.
*/
public static Initializer byCallWithParams(CtClass methodClass,
String methodName, String[] stringParams) {
MethodInitializer i = new MethodInitializer();
i.objectType = methodClass;
i.methodName = methodName;
i.stringParams = stringParams;
i.withConstructorParams = true;
return i;
}
Makes an initializer creating a new array.
Params: - type – the type of the array.
- size – the size of the array.
Throws: - NotFoundException – if the type of the array components
is not found.
/**
* Makes an initializer creating a new array.
*
* @param type the type of the array.
* @param size the size of the array.
* @throws NotFoundException if the type of the array components
* is not found.
*/
public static Initializer byNewArray(CtClass type, int size)
throws NotFoundException
{
return new ArrayInitializer(type.getComponentType(), size);
}
Makes an initializer creating a new multi-dimensional array.
Params: - type – the type of the array.
- sizes – an
int
array of the size in every
dimension.
The first element is the size in the first
dimension. The second is in the second, etc.
/**
* Makes an initializer creating a new multi-dimensional array.
*
* @param type the type of the array.
* @param sizes an <code>int</code> array of the size in every
* dimension.
* The first element is the size in the first
* dimension. The second is in the second, etc.
*/
public static Initializer byNewArray(CtClass type, int[] sizes) {
return new MultiArrayInitializer(type, sizes);
}
Makes an initializer.
Params: - source – initializer expression.
/**
* Makes an initializer.
*
* @param source initializer expression.
*/
public static Initializer byExpr(String source) {
return new CodeInitializer(source);
}
static Initializer byExpr(ASTree source) {
return new PtreeInitializer(source);
}
// Check whether this initializer is valid for the field type.
// If it is invaild, this method throws an exception.
void check(String desc) throws CannotCompileException {}
// produce codes for initialization
abstract int compile(CtClass type, String name, Bytecode code,
CtClass[] parameters, Javac drv)
throws CannotCompileException;
// produce codes for initialization
abstract int compileIfStatic(CtClass type, String name,
Bytecode code, Javac drv) throws CannotCompileException;
// returns the index of CONSTANT_Integer_info etc
// if the value is constant. Otherwise, 0.
int getConstantValue(ConstPool cp, CtClass type) { return 0; }
}
static abstract class CodeInitializer0 extends Initializer {
abstract void compileExpr(Javac drv) throws CompileError;
@Override
int compile(CtClass type, String name, Bytecode code,
CtClass[] parameters, Javac drv)
throws CannotCompileException
{
try {
code.addAload(0);
compileExpr(drv);
code.addPutfield(Bytecode.THIS, name, Descriptor.of(type));
return code.getMaxStack();
}
catch (CompileError e) {
throw new CannotCompileException(e);
}
}
@Override
int compileIfStatic(CtClass type, String name, Bytecode code,
Javac drv) throws CannotCompileException
{
try {
compileExpr(drv);
code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type));
return code.getMaxStack();
}
catch (CompileError e) {
throw new CannotCompileException(e);
}
}
int getConstantValue2(ConstPool cp, CtClass type, ASTree tree) {
if (type.isPrimitive()) {
if (tree instanceof IntConst) {
long value = ((IntConst)tree).get();
if (type == CtClass.doubleType)
return cp.addDoubleInfo(value);
else if (type == CtClass.floatType)
return cp.addFloatInfo(value);
else if (type == CtClass.longType)
return cp.addLongInfo(value);
else if (type != CtClass.voidType)
return cp.addIntegerInfo((int)value);
}
else if (tree instanceof DoubleConst) {
double value = ((DoubleConst)tree).get();
if (type == CtClass.floatType)
return cp.addFloatInfo((float)value);
else if (type == CtClass.doubleType)
return cp.addDoubleInfo(value);
}
}
else if (tree instanceof StringL
&& type.getName().equals(javaLangString))
return cp.addStringInfo(((StringL)tree).get());
return 0;
}
}
static class CodeInitializer extends CodeInitializer0 {
private String expression;
CodeInitializer(String expr) { expression = expr; }
@Override
void compileExpr(Javac drv) throws CompileError {
drv.compileExpr(expression);
}
@Override
int getConstantValue(ConstPool cp, CtClass type) {
try {
ASTree t = Javac.parseExpr(expression, new SymbolTable());
return getConstantValue2(cp, type, t);
}
catch (CompileError e) {
return 0;
}
}
}
static class PtreeInitializer extends CodeInitializer0 {
private ASTree expression;
PtreeInitializer(ASTree expr) { expression = expr; }
@Override
void compileExpr(Javac drv) throws CompileError {
drv.compileExpr(expression);
}
@Override
int getConstantValue(ConstPool cp, CtClass type) {
return getConstantValue2(cp, type, expression);
}
}
A field initialized with a parameter passed to the constructor
of the class containing that field.
/**
* A field initialized with a parameter passed to the constructor
* of the class containing that field.
*/
static class ParamInitializer extends Initializer {
int nthParam;
ParamInitializer() {}
@Override
int compile(CtClass type, String name, Bytecode code,
CtClass[] parameters, Javac drv)
throws CannotCompileException
{
if (parameters != null && nthParam < parameters.length) {
code.addAload(0);
int nth = nthParamToLocal(nthParam, parameters, false);
int s = code.addLoad(nth, type) + 1;
code.addPutfield(Bytecode.THIS, name, Descriptor.of(type));
return s; // stack size
}
return 0; // do not initialize
}
Computes the index of the local variable that the n-th parameter
is assigned to.
Params: - nth – n-th parameter
- params – list of parameter types
- isStatic – true if the method is static.
/**
* Computes the index of the local variable that the n-th parameter
* is assigned to.
*
* @param nth n-th parameter
* @param params list of parameter types
* @param isStatic true if the method is static.
*/
static int nthParamToLocal(int nth, CtClass[] params,
boolean isStatic) {
CtClass longType = CtClass.longType;
CtClass doubleType = CtClass.doubleType;
int k;
if (isStatic)
k = 0;
else
k = 1; // 0 is THIS.
for (int i = 0; i < nth; ++i) {
CtClass type = params[i];
if (type == longType || type == doubleType)
k += 2;
else
++k;
}
return k;
}
@Override
int compileIfStatic(CtClass type, String name, Bytecode code,
Javac drv) throws CannotCompileException
{
return 0;
}
}
A field initialized with an object created by the new operator.
/**
* A field initialized with an object created by the new operator.
*/
static class NewInitializer extends Initializer {
CtClass objectType;
String[] stringParams;
boolean withConstructorParams;
NewInitializer() {}
Produces codes in which a new object is created and assigned to
the field as the initial value.
/**
* Produces codes in which a new object is created and assigned to
* the field as the initial value.
*/
@Override
int compile(CtClass type, String name, Bytecode code,
CtClass[] parameters, Javac drv)
throws CannotCompileException
{
int stacksize;
code.addAload(0);
code.addNew(objectType);
code.add(Bytecode.DUP);
code.addAload(0);
if (stringParams == null)
stacksize = 4;
else
stacksize = compileStringParameter(code) + 4;
if (withConstructorParams)
stacksize += CtNewWrappedMethod.compileParameterList(code,
parameters, 1);
code.addInvokespecial(objectType, "<init>", getDescriptor());
code.addPutfield(Bytecode.THIS, name, Descriptor.of(type));
return stacksize;
}
private String getDescriptor() {
final String desc3
= "(Ljava/lang/Object;[Ljava/lang/String;[Ljava/lang/Object;)V";
if (stringParams == null)
if (withConstructorParams)
return "(Ljava/lang/Object;[Ljava/lang/Object;)V";
else
return "(Ljava/lang/Object;)V";
if (withConstructorParams)
return desc3;
return "(Ljava/lang/Object;[Ljava/lang/String;)V";
}
Produces codes for a static field.
/**
* Produces codes for a static field.
*/
@Override
int compileIfStatic(CtClass type, String name, Bytecode code,
Javac drv) throws CannotCompileException
{
String desc;
code.addNew(objectType);
code.add(Bytecode.DUP);
int stacksize = 2;
if (stringParams == null)
desc = "()V";
else {
desc = "([Ljava/lang/String;)V";
stacksize += compileStringParameter(code);
}
code.addInvokespecial(objectType, "<init>", desc);
code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type));
return stacksize;
}
protected final int compileStringParameter(Bytecode code)
throws CannotCompileException
{
int nparam = stringParams.length;
code.addIconst(nparam);
code.addAnewarray(javaLangString);
for (int j = 0; j < nparam; ++j) {
code.add(Bytecode.DUP); // dup
code.addIconst(j); // iconst_<j>
code.addLdc(stringParams[j]); // ldc ...
code.add(Bytecode.AASTORE); // aastore
}
return 4;
}
}
A field initialized with the result of a static method call.
/**
* A field initialized with the result of a static method call.
*/
static class MethodInitializer extends NewInitializer {
String methodName;
// the method class is specified by objectType.
MethodInitializer() {}
Produces codes in which a new object is created and assigned to
the field as the initial value.
/**
* Produces codes in which a new object is created and assigned to
* the field as the initial value.
*/
@Override
int compile(CtClass type, String name, Bytecode code,
CtClass[] parameters, Javac drv)
throws CannotCompileException
{
int stacksize;
code.addAload(0);
code.addAload(0);
if (stringParams == null)
stacksize = 2;
else
stacksize = compileStringParameter(code) + 2;
if (withConstructorParams)
stacksize += CtNewWrappedMethod.compileParameterList(code,
parameters, 1);
String typeDesc = Descriptor.of(type);
String mDesc = getDescriptor() + typeDesc;
code.addInvokestatic(objectType, methodName, mDesc);
code.addPutfield(Bytecode.THIS, name, typeDesc);
return stacksize;
}
private String getDescriptor() {
final String desc3
= "(Ljava/lang/Object;[Ljava/lang/String;[Ljava/lang/Object;)";
if (stringParams == null)
if (withConstructorParams)
return "(Ljava/lang/Object;[Ljava/lang/Object;)";
else
return "(Ljava/lang/Object;)";
if (withConstructorParams)
return desc3;
return "(Ljava/lang/Object;[Ljava/lang/String;)";
}
Produces codes for a static field.
/**
* Produces codes for a static field.
*/
@Override
int compileIfStatic(CtClass type, String name, Bytecode code,
Javac drv) throws CannotCompileException
{
String desc;
int stacksize = 1;
if (stringParams == null)
desc = "()";
else {
desc = "([Ljava/lang/String;)";
stacksize += compileStringParameter(code);
}
String typeDesc = Descriptor.of(type);
code.addInvokestatic(objectType, methodName, desc + typeDesc);
code.addPutstatic(Bytecode.THIS, name, typeDesc);
return stacksize;
}
}
static class IntInitializer extends Initializer {
int value;
IntInitializer(int v) { value = v; }
@Override
void check(String desc) throws CannotCompileException {
char c = desc.charAt(0);
if (c != 'I' && c != 'S' && c != 'B' && c != 'C' && c != 'Z')
throw new CannotCompileException("type mismatch");
}
@Override
int compile(CtClass type, String name, Bytecode code,
CtClass[] parameters, Javac drv)
throws CannotCompileException
{
code.addAload(0);
code.addIconst(value);
code.addPutfield(Bytecode.THIS, name, Descriptor.of(type));
return 2; // stack size
}
@Override
int compileIfStatic(CtClass type, String name, Bytecode code,
Javac drv) throws CannotCompileException
{
code.addIconst(value);
code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type));
return 1; // stack size
}
@Override
int getConstantValue(ConstPool cp, CtClass type) {
return cp.addIntegerInfo(value);
}
}
static class LongInitializer extends Initializer {
long value;
LongInitializer(long v) { value = v; }
@Override
void check(String desc) throws CannotCompileException {
if (!desc.equals("J"))
throw new CannotCompileException("type mismatch");
}
@Override
int compile(CtClass type, String name, Bytecode code,
CtClass[] parameters, Javac drv)
throws CannotCompileException
{
code.addAload(0);
code.addLdc2w(value);
code.addPutfield(Bytecode.THIS, name, Descriptor.of(type));
return 3; // stack size
}
@Override
int compileIfStatic(CtClass type, String name, Bytecode code,
Javac drv) throws CannotCompileException
{
code.addLdc2w(value);
code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type));
return 2; // stack size
}
@Override
int getConstantValue(ConstPool cp, CtClass type) {
if (type == CtClass.longType)
return cp.addLongInfo(value);
return 0;
}
}
static class FloatInitializer extends Initializer {
float value;
FloatInitializer(float v) { value = v; }
@Override
void check(String desc) throws CannotCompileException {
if (!desc.equals("F"))
throw new CannotCompileException("type mismatch");
}
@Override
int compile(CtClass type, String name, Bytecode code,
CtClass[] parameters, Javac drv)
throws CannotCompileException
{
code.addAload(0);
code.addFconst(value);
code.addPutfield(Bytecode.THIS, name, Descriptor.of(type));
return 3; // stack size
}
@Override
int compileIfStatic(CtClass type, String name, Bytecode code,
Javac drv) throws CannotCompileException
{
code.addFconst(value);
code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type));
return 2; // stack size
}
@Override
int getConstantValue(ConstPool cp, CtClass type) {
if (type == CtClass.floatType)
return cp.addFloatInfo(value);
return 0;
}
}
static class DoubleInitializer extends Initializer {
double value;
DoubleInitializer(double v) { value = v; }
@Override
void check(String desc) throws CannotCompileException {
if (!desc.equals("D"))
throw new CannotCompileException("type mismatch");
}
@Override
int compile(CtClass type, String name, Bytecode code,
CtClass[] parameters, Javac drv)
throws CannotCompileException
{
code.addAload(0);
code.addLdc2w(value);
code.addPutfield(Bytecode.THIS, name, Descriptor.of(type));
return 3; // stack size
}
@Override
int compileIfStatic(CtClass type, String name, Bytecode code,
Javac drv) throws CannotCompileException
{
code.addLdc2w(value);
code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type));
return 2; // stack size
}
@Override
int getConstantValue(ConstPool cp, CtClass type) {
if (type == CtClass.doubleType)
return cp.addDoubleInfo(value);
return 0;
}
}
static class StringInitializer extends Initializer {
String value;
StringInitializer(String v) { value = v; }
@Override
int compile(CtClass type, String name, Bytecode code,
CtClass[] parameters, Javac drv)
throws CannotCompileException
{
code.addAload(0);
code.addLdc(value);
code.addPutfield(Bytecode.THIS, name, Descriptor.of(type));
return 2; // stack size
}
@Override
int compileIfStatic(CtClass type, String name, Bytecode code,
Javac drv) throws CannotCompileException
{
code.addLdc(value);
code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type));
return 1; // stack size
}
@Override
int getConstantValue(ConstPool cp, CtClass type) {
if (type.getName().equals(javaLangString))
return cp.addStringInfo(value);
return 0;
}
}
static class ArrayInitializer extends Initializer {
CtClass type;
int size;
ArrayInitializer(CtClass t, int s) { type = t; size = s; }
private void addNewarray(Bytecode code) {
if (type.isPrimitive())
code.addNewarray(((CtPrimitiveType)type).getArrayType(),
size);
else
code.addAnewarray(type, size);
}
@Override
int compile(CtClass type, String name, Bytecode code,
CtClass[] parameters, Javac drv)
throws CannotCompileException
{
code.addAload(0);
addNewarray(code);
code.addPutfield(Bytecode.THIS, name, Descriptor.of(type));
return 2; // stack size
}
@Override
int compileIfStatic(CtClass type, String name, Bytecode code,
Javac drv) throws CannotCompileException
{
addNewarray(code);
code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type));
return 1; // stack size
}
}
static class MultiArrayInitializer extends Initializer {
CtClass type;
int[] dim;
MultiArrayInitializer(CtClass t, int[] d) { type = t; dim = d; }
@Override
void check(String desc) throws CannotCompileException {
if (desc.charAt(0) != '[')
throw new CannotCompileException("type mismatch");
}
@Override
int compile(CtClass type, String name, Bytecode code,
CtClass[] parameters, Javac drv)
throws CannotCompileException
{
code.addAload(0);
int s = code.addMultiNewarray(type, dim);
code.addPutfield(Bytecode.THIS, name, Descriptor.of(type));
return s + 1; // stack size
}
@Override
int compileIfStatic(CtClass type, String name, Bytecode code,
Javac drv) throws CannotCompileException
{
int s = code.addMultiNewarray(type, dim);
code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type));
return s; // stack size
}
}
}