/*******************************************************************************
* Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Oracle - initial API and implementation from Oracle TopLink
******************************************************************************/
package org.eclipse.persistence.tools.workbench.utility.classfile;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Modifier;
import org.eclipse.persistence.tools.workbench.utility.ClassTools;
import org.eclipse.persistence.tools.workbench.utility.classfile.tools.ClassFileDataInputStream;
import org.eclipse.persistence.tools.workbench.utility.io.IndentingPrintWriter;
/**
* This class models a class file member (field or method):
* u2 access_flags;
* u2 name_index;
* u2 descriptor_index;
* u2 attributes_count;
* attribute_info[attributes_count] attributes;
*
* See "The Java Virtual Machine Specification" Chapter 4.
*/
public abstract class Member {
private Pool pool;
private short accessFlags;
/** these flags will match those returned by java.lang.Field/Method#getModifiers() */
private short standardAccessFlags;
private short nameIndex;
private short descriptorIndex;
private AttributePool attributePool;
/** constants defined in "The Java Virtual Machine Specification" */
public static final short ACC_SYNTHETIC = 0x1000;
/**
* Construct a class file member from the specified stream
* of byte codes.
*/
Member(ClassFileDataInputStream stream, Pool pool) throws IOException {
super();
this.pool = pool;
this.initialize(stream);
}
void initialize(ClassFileDataInputStream stream) throws IOException {
this.accessFlags = stream.readU2();
this.standardAccessFlags = this.buildStandardAccessFlags();
this.nameIndex = stream.readU2();
this.descriptorIndex = stream.readU2();
this.attributePool = new AttributePool(stream, this.classFile());
}
private short buildStandardAccessFlags() {
short result = this.accessFlags;
// clear any unsupported bits
result &= this.visibleAccessFlagsMask();
return result;
}
/**
* Return a mask that will preserve only those bits properly recognized
* by the java.lang.reflect.Modifier.toString() method.
*/
abstract short visibleAccessFlagsMask();
public String displayString() {
StringWriter sw = new StringWriter(1000);
IndentingPrintWriter writer = new IndentingPrintWriter(sw);
this.displayStringOn(writer);
return sw.toString();
}
public void displayStringOn(IndentingPrintWriter writer) {
this.printDeclarationOn(writer);
// writer.print(" (");
// writer.print(this.descriptor());
// writer.print(")");
writer.println();
writer.indent();
this.attributePool.displayStringOn(writer);
writer.undent();
}
public abstract void printDeclarationOn(PrintWriter writer);
void printModifierOn(PrintWriter writer) {
String modifierString = this.modifierString();
if (modifierString.length() != 0) {
writer.print(modifierString);
writer.print(' ');
}
}
public void accept(Visitor visitor) {
this.attributePool.accept(visitor);
}
public String modifierString() {
return Modifier.toString(this.standardAccessFlags);
}
public String name() {
return this.constantPool().getUTF8String(this.nameIndex);
}
public String descriptor() {
return this.constantPool().getUTF8String(this.descriptorIndex);
}
public boolean isDeprecated() {
return this.attributePool.isDeprecated();
}
/**
* "A class member that does not appear in the source code
* must be marked using a Synthetic attribute, or else it must
* have its ACC_SYNTHETIC bit set."
*/
public boolean isSynthetic() {
return this.isMarkedSyntheticByAccessFlag() || this.isMarkedSyntheticByAttribute();
}
/**
* Check a bit that cannot (yet?) be interpreted by the
* Modifier static methods. This bit indicates the member
* is "not present in the source code".
*/
public boolean isMarkedSyntheticByAccessFlag() {
return (this.accessFlags & ACC_SYNTHETIC) != 0;
}
public boolean isMarkedSyntheticByAttribute() {
return this.attributePool.isSynthetic();
}
public Pool getPool() {
return this.pool;
}
public ClassFile classFile() {
return this.pool.getClassFile();
}
public String declaringClassName() {
return this.classFile().className();
}
public ConstantPool constantPool() {
return this.classFile().getConstantPool();
}
/**
* Return the set of flags that will match those
* returned by java.lang.Class#getModifiers()
*/
public short standardAccessFlags() {
return this.standardAccessFlags;
}
public short getAccessFlags() {
return this.accessFlags;
}
public short getNameIndex() {
return this.nameIndex;
}
public short getDescriptorIndex() {
return this.descriptorIndex;
}
public AttributePool getAttributePool() {
return this.attributePool;
}
public final String toString() {
StringWriter sw = new StringWriter(200);
PrintWriter pw = new PrintWriter(sw);
pw.print(ClassTools.shortClassNameForObject(this));
pw.print('(');
this.printDeclarationOn(pw);
pw.print(')');
return sw.toString();
}
// ********** member interface **********
/**
* backpointer interface for members (fields and methods)
*/
public interface Pool {
ClassFile getClassFile();
}
}