improved java bytecode reader (nearly complete)
This commit is contained in:
parent
78940c4469
commit
0763ad1fd6
18 changed files with 396 additions and 262 deletions
12
src/main/java/nl/sander/jsontoy2/AccesModifiers.java
Normal file
12
src/main/java/nl/sander/jsontoy2/AccesModifiers.java
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
package nl.sander.jsontoy2;
|
||||
|
||||
public class AccesModifiers {
|
||||
public final static int ACC_PUBLIC = 0x0001; // Declared public; may be accessed from outside its package.
|
||||
public final static int ACC_FINAL = 0x0010; // Declared final; no subclasses allowed.
|
||||
public final static int ACC_SUPER = 0x0020; // Treat superclass methods specially when invoked by the invokespecial instruction.
|
||||
public final static int ACC_INTERFACE = 0x0200; // Is an interface, not a class.
|
||||
public final static int ACC_ABSTRACT = 0x0400; // Declared abstract; must not be instantiated.
|
||||
public final static int ACC_SYNTHETIC = 0x1000; // Declared synthetic; not present in the source code.
|
||||
public final static int ACC_ANNOTATION = 0x2000; // Declared as an annotation type.
|
||||
public final static int ACC_ENUM = 0x4000; // Declared as an enum type.
|
||||
}
|
||||
11
src/main/java/nl/sander/jsontoy2/java/AttributeInfo.java
Normal file
11
src/main/java/nl/sander/jsontoy2/java/AttributeInfo.java
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
package nl.sander.jsontoy2.java;
|
||||
|
||||
public class AttributeInfo {
|
||||
private final int nameIndex;
|
||||
private final byte[] info;
|
||||
|
||||
public AttributeInfo(int nameIndex, byte[] info) {
|
||||
this.nameIndex = nameIndex;
|
||||
this.info = info;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package nl.sander.jsontoy2.java;
|
||||
|
||||
import nl.sander.jsontoy2.java.constantpool.*;
|
||||
import nl.sander.jsontoy2.java.constantpool.ConstantPoolEntry;
|
||||
import nl.sander.jsontoy2.java.constantpool.Utf8Entry;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
|
|
@ -9,116 +10,73 @@ import java.util.stream.Collectors;
|
|||
|
||||
public class ClassObject<T> {
|
||||
|
||||
private int constantPoolCount;
|
||||
private ConstantPoolEntry[] constantPool;
|
||||
private int constantPoolIndex = 0;
|
||||
private Info[] fieldInfos;
|
||||
private Info[] methodInfos;
|
||||
|
||||
public int getConstantPoolCount() {
|
||||
return constantPoolCount;
|
||||
private String getUtf8(int index) {
|
||||
return ((Utf8Entry) constantPool[index - 1]).getUtf8();
|
||||
}
|
||||
|
||||
public Set<Field> getFields() {
|
||||
return Arrays.stream(fieldInfos)
|
||||
.map(fi -> new Field(getUtf8(fi.getNameIndex()), getUtf8(fi.getDescriptorIndex())))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public Set<Method> getMethods() {
|
||||
return Arrays.stream(methodInfos)
|
||||
.map(mi -> new Method(getUtf8(mi.getNameIndex()), getUtf8(mi.getDescriptorIndex())))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < constantPoolCount - 1; i++) {
|
||||
ConstantPoolEntry entry = constantPool[i];
|
||||
for (ConstantPoolEntry entry : constantPool) {
|
||||
builder.append(entry.toString());
|
||||
builder.append(String.format("%n"));
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private void add(ConstantPoolEntry entry) {
|
||||
constantPool[constantPoolIndex++] = entry;
|
||||
}
|
||||
|
||||
public Set<Field> getFields() {
|
||||
return Arrays.stream(constantPool)
|
||||
.filter(e -> e instanceof FieldRefEntry)
|
||||
.map(FieldRefEntry.class::cast)
|
||||
.map(f -> {
|
||||
NameAndType nat = getNameAndType(f);
|
||||
return new Field(nat.getName(), nat.getType());
|
||||
})
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private NameAndType getNameAndType(FieldRefEntry f) {
|
||||
NameAndTypeEntry natEntry = (NameAndTypeEntry) constantPool[f.getNameAndTypeIndex() - 1];
|
||||
return new NameAndType(getUtf8(natEntry.getNameIndex()), getUtf8(natEntry.getTypeIndex()));
|
||||
}
|
||||
|
||||
private String getUtf8(short index) {
|
||||
return ((Utf8Entry) constantPool[index - 1]).getUtf8();
|
||||
}
|
||||
|
||||
public static class Builder<T> {
|
||||
|
||||
private final ClassObject<T> classObject = new ClassObject<>();
|
||||
private int constantPoolIndex = 0;
|
||||
private int fieldInfoIndex = 0;
|
||||
private int methodInfoIndex = 0;
|
||||
|
||||
public ClassObject<T> build() {
|
||||
return classObject;
|
||||
}
|
||||
|
||||
public Builder<T> constantPoolCount(int constantPoolCount) {
|
||||
classObject.constantPoolCount = constantPoolCount;
|
||||
classObject.constantPool = new ConstantPoolEntry[constantPoolCount];
|
||||
classObject.constantPool = new ConstantPoolEntry[constantPoolCount - 1];
|
||||
return this;
|
||||
}
|
||||
|
||||
public void constantPoolEntry(String utf8) {
|
||||
classObject.add(new Utf8Entry(utf8));
|
||||
void constantPoolEntry(ConstantPoolEntry entry) {
|
||||
classObject.constantPool[constantPoolIndex++] = entry;
|
||||
}
|
||||
|
||||
public void constantPoolEntry(int i) {
|
||||
classObject.add(new IntEntry(i));
|
||||
public Builder<T> fieldInfoCount(int fieldInfoCount) {
|
||||
classObject.fieldInfos = new Info[fieldInfoCount];
|
||||
return this;
|
||||
}
|
||||
|
||||
public void constantPoolEntry(float f) {
|
||||
classObject.add(new FloatEntry(f));
|
||||
public Builder<T> fieldInfo(Info fieldInfo) {
|
||||
classObject.fieldInfos[fieldInfoIndex++] = fieldInfo;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void constantPoolEntry(long f) {
|
||||
classObject.add(new LongEntry(f));
|
||||
public Builder<T> methodInfoCount(int methodInfoCount) {
|
||||
classObject.methodInfos = new Info[methodInfoCount];
|
||||
return this;
|
||||
}
|
||||
|
||||
public void constantPoolEntry(double d) {
|
||||
classObject.add(new DoubleEntry(d));
|
||||
}
|
||||
|
||||
public void constantPoolClassEntry(short nameIndex) {
|
||||
classObject.add(new ClassEntry(nameIndex));
|
||||
}
|
||||
|
||||
public void constantPoolStringEntry(short utf8Index) {
|
||||
classObject.add(new StringEntry(utf8Index));
|
||||
}
|
||||
|
||||
public void constantPoolFieldRefEntry(short classIndex, short nameAndTypeIndex) {
|
||||
classObject.add(new FieldRefEntry(classIndex, nameAndTypeIndex));
|
||||
}
|
||||
|
||||
public void constantPoolMethodRefEntry(short classIndex, short nameAndTypeIndex) {
|
||||
classObject.add(new MethodRefEntry(classIndex, nameAndTypeIndex));
|
||||
}
|
||||
|
||||
public void constantPoolInterfaceMethodRefEntry(short classIndex, short nameAndTypeIndex) {
|
||||
classObject.add(new InterfaceMethodRefEntry(classIndex, nameAndTypeIndex));
|
||||
}
|
||||
|
||||
public void constantPoolNameAndTypeEntry(short nameIndex, short typeIndex) {
|
||||
classObject.add(new NameAndTypeEntry(nameIndex, typeIndex));
|
||||
}
|
||||
|
||||
public void constantPoolMethodHandleEntry(short referenceKind, short referenceIndex) {
|
||||
classObject.add(new MethodHandleEntry(referenceKind, referenceIndex));
|
||||
}
|
||||
|
||||
public void constantPoolMethodTypeEntry(short descriptorIndex) {
|
||||
classObject.add(new MethodTypeEntry(descriptorIndex));
|
||||
}
|
||||
|
||||
public void constantPoolInvokeDynamicEntry(short bootstrapMethodAttrIndex, short nameAndTypeIndex) {
|
||||
classObject.add(new InvokeDynamicEntry(bootstrapMethodAttrIndex, nameAndTypeIndex));
|
||||
public Builder<T> methodInfo(Info methodInfo) {
|
||||
classObject.methodInfos[methodInfoIndex++] = methodInfo;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,152 +0,0 @@
|
|||
package nl.sander.jsontoy2.java;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class ClassParser {
|
||||
|
||||
public <T> ClassObject<T> parse(Class<T> type) {
|
||||
DataInputStream in = new DataInputStream(new BufferedInputStream(type.getResourceAsStream(getResourceName(type))));
|
||||
expect(in, 0xCAFEBABE);
|
||||
ClassObject.Builder<T> builder = new ClassObject.Builder<>();
|
||||
skip(in, 4); //skip version
|
||||
int constantPoolCount = readShort(in);
|
||||
builder.constantPoolCount(constantPoolCount);
|
||||
for (int i = 1; i < constantPoolCount; i++) {
|
||||
readConstantPoolEntry(in, builder);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private <T> void readConstantPoolEntry(DataInputStream in, ClassObject.Builder<T> builder) {
|
||||
byte tag = readByte(in);
|
||||
switch (tag) {
|
||||
case 1: readUtf8(in, builder);
|
||||
break;
|
||||
case 2: throw new IllegalStateException("2: invalid classpool tag");
|
||||
case 3: builder.constantPoolEntry(readInt(in));
|
||||
break;
|
||||
case 4: builder.constantPoolEntry(readFloat(in));
|
||||
break;
|
||||
case 5: builder.constantPoolEntry(readLong(in));
|
||||
break;
|
||||
case 6: builder.constantPoolEntry(readDouble(in));
|
||||
break;
|
||||
case 7: builder.constantPoolClassEntry(readShort(in));
|
||||
break;
|
||||
case 8: builder.constantPoolStringEntry(readShort(in));
|
||||
break;
|
||||
case 9: builder.constantPoolFieldRefEntry(readShort(in), readShort(in));
|
||||
break;
|
||||
case 10: builder.constantPoolMethodRefEntry(readShort(in), readShort(in));
|
||||
break;
|
||||
case 11: builder.constantPoolInterfaceMethodRefEntry(readShort(in), readShort(in));
|
||||
break;
|
||||
case 12: builder.constantPoolNameAndTypeEntry(readShort(in), readShort(in));
|
||||
break;
|
||||
case 15: builder.constantPoolMethodHandleEntry(readShort(in), readShort(in));
|
||||
break;
|
||||
case 16: builder.constantPoolMethodTypeEntry(readShort(in));
|
||||
break;
|
||||
case 18: builder.constantPoolInvokeDynamicEntry(readShort(in), readShort(in));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void readUtf8(DataInputStream in, ClassObject.Builder<?> builder) {
|
||||
short length = readShort(in);
|
||||
String utf8 = readString(in, length);
|
||||
builder.constantPoolEntry(utf8);
|
||||
}
|
||||
|
||||
private String readString(DataInputStream in, short length) {
|
||||
try {
|
||||
byte[] bytes = in.readNBytes(length);
|
||||
return new String(bytes, StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
private long skip(InputStream in, long bytecount) {
|
||||
try {
|
||||
return in.skip(bytecount);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private byte readByte(DataInputStream in) {
|
||||
try {
|
||||
return in.readByte();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private short readShort(DataInputStream in) {
|
||||
try {
|
||||
return in.readShort();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private int readInt(DataInputStream in) {
|
||||
try {
|
||||
return in.readInt();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private float readFloat(DataInputStream in) {
|
||||
try {
|
||||
return in.readFloat();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private long readLong(DataInputStream in) {
|
||||
try {
|
||||
return in.readLong();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private double readDouble(DataInputStream in) {
|
||||
try {
|
||||
return in.readDouble();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void expect(DataInputStream in, int expected) {
|
||||
try {
|
||||
int i = in.readInt();
|
||||
if (i != expected) {
|
||||
throw new IllegalStateException("class file not valid");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> String getResourceName(Class<T> type) {
|
||||
StringBuilder typeName = new StringBuilder("/" + type.getName());
|
||||
|
||||
for (int i = 0; i < typeName.length(); i++) {
|
||||
if (typeName.charAt(i) == '.') {
|
||||
typeName.setCharAt(i, '/');
|
||||
}
|
||||
}
|
||||
typeName.append(".class");
|
||||
return typeName.toString();
|
||||
}
|
||||
}
|
||||
123
src/main/java/nl/sander/jsontoy2/java/ClassReader.java
Normal file
123
src/main/java/nl/sander/jsontoy2/java/ClassReader.java
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
package nl.sander.jsontoy2.java;
|
||||
|
||||
import nl.sander.jsontoy2.java.constantpool.*;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class ClassReader extends DataReader {
|
||||
|
||||
public <T> ClassObject<T> parse(Class<T> type) {
|
||||
DataInputStream in = new DataInputStream(new BufferedInputStream(type.getResourceAsStream(getResourceName(type))));
|
||||
expect(in, 0xCAFEBABE);
|
||||
|
||||
ClassObject.Builder<T> builder = new ClassObject.Builder<>();
|
||||
|
||||
skip(in, 4); // u2 minor_version, u2 major_version
|
||||
|
||||
readConstantPool(in, builder);
|
||||
|
||||
skip(in, 6); // u2 access_flags, u2 this_class, u2 super_class
|
||||
int interfacesCount = readUnsignedShort(in);
|
||||
skip(in, interfacesCount * 2); // interfaces[]
|
||||
|
||||
readFields(in, builder);
|
||||
readMethods(in, builder);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private <T> void readConstantPool(DataInputStream in, ClassObject.Builder<T> builder) {
|
||||
int constantPoolCount = readUnsignedShort(in);
|
||||
builder.constantPoolCount(constantPoolCount);
|
||||
for (int i = 1; i < constantPoolCount; i++) {
|
||||
builder.constantPoolEntry(readConstantPoolEntry(in));
|
||||
}
|
||||
}
|
||||
|
||||
private <T> void readFields(DataInputStream in, ClassObject.Builder<T> builder) {
|
||||
int fieldInfoCount = readUnsignedShort(in);
|
||||
builder.fieldInfoCount(fieldInfoCount);
|
||||
for (int i = 0; i < fieldInfoCount; i++) {
|
||||
builder.fieldInfo(readField(in));
|
||||
}
|
||||
}
|
||||
|
||||
private <T> void readMethods(DataInputStream in, ClassObject.Builder<T> builder) {
|
||||
int methodInfoCount = readUnsignedShort(in);
|
||||
builder.methodInfoCount(methodInfoCount);
|
||||
for (int i = 0; i < methodInfoCount; i++) {
|
||||
builder.methodInfo(readMethod(in));
|
||||
}
|
||||
}
|
||||
|
||||
private <T> Info readField(DataInputStream in) {
|
||||
Info fieldInfo = new Info(readUnsignedShort(in), readUnsignedShort(in), readUnsignedShort(in), readUnsignedShort(in));
|
||||
for (int i = 0; i < fieldInfo.getAttributesCount(); i++) {
|
||||
fieldInfo.add(readAttribute(in));
|
||||
}
|
||||
|
||||
return fieldInfo;
|
||||
}
|
||||
|
||||
private <T> Info readMethod(DataInputStream in) {
|
||||
Info methodInfo = new Info(readUnsignedShort(in), readUnsignedShort(in), readUnsignedShort(in), readUnsignedShort(in));
|
||||
for (int i = 0; i < methodInfo.getAttributesCount(); i++) {
|
||||
methodInfo.add(readAttribute(in));
|
||||
}
|
||||
|
||||
return methodInfo;
|
||||
}
|
||||
|
||||
private AttributeInfo readAttribute(DataInputStream in) {
|
||||
int attributeNameIndex = readUnsignedShort(in);
|
||||
int attributeLength = readInt(in);
|
||||
byte[] info;
|
||||
if (attributeLength > 0) {
|
||||
info = new byte[attributeLength];
|
||||
try {
|
||||
in.readFully(info);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
info = new byte[0];
|
||||
}
|
||||
return new AttributeInfo(attributeNameIndex, info);
|
||||
}
|
||||
|
||||
private <T> ConstantPoolEntry readConstantPoolEntry(DataInputStream in) {
|
||||
byte tag = readByte(in);
|
||||
switch (tag) {
|
||||
case 1: return readUtf8Entry(in);
|
||||
case 2: throw new IllegalStateException("2: invalid classpool tag");
|
||||
case 3: return new IntEntry(readInt(in));
|
||||
case 4: return new FloatEntry(readFloat(in));
|
||||
case 5: return new LongEntry(readLong(in));
|
||||
case 6: return new DoubleEntry(readDouble(in));
|
||||
case 7: return new ClassEntry(readUnsignedShort(in));
|
||||
case 8: return new StringEntry(readUnsignedShort(in));
|
||||
case 9: return new FieldRefEntry(readShort(in), readShort(in));
|
||||
case 10: return new MethodRefEntry(readUnsignedShort(in), readUnsignedShort(in));
|
||||
case 11: return new InterfaceMethodRefEntry(readUnsignedShort(in), readUnsignedShort(in));
|
||||
case 12: return new NameAndTypeEntry(readUnsignedShort(in), readUnsignedShort(in));
|
||||
case 15: return new MethodHandleEntry(readUnsignedShort(in), readUnsignedShort(in));
|
||||
case 16: return new MethodTypeEntry(readUnsignedShort(in));
|
||||
case 18: return new InvokeDynamicEntry(readUnsignedShort(in), readUnsignedShort(in));
|
||||
default: throw new IllegalStateException("invalid classpool");
|
||||
}
|
||||
}
|
||||
|
||||
protected <T> String getResourceName(Class<T> type) {
|
||||
StringBuilder typeName = new StringBuilder("/" + type.getName());
|
||||
|
||||
for (int i = 0; i < typeName.length(); i++) {
|
||||
if (typeName.charAt(i) == '.') {
|
||||
typeName.setCharAt(i, '/');
|
||||
}
|
||||
}
|
||||
typeName.append(".class");
|
||||
return typeName.toString();
|
||||
}
|
||||
}
|
||||
100
src/main/java/nl/sander/jsontoy2/java/DataReader.java
Normal file
100
src/main/java/nl/sander/jsontoy2/java/DataReader.java
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
package nl.sander.jsontoy2.java;
|
||||
|
||||
import nl.sander.jsontoy2.java.constantpool.Utf8Entry;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class DataReader {
|
||||
|
||||
protected float readFloat(DataInputStream in) {
|
||||
try {
|
||||
return in.readFloat();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
protected Utf8Entry readUtf8Entry(DataInputStream in) {
|
||||
short length = readShort(in);
|
||||
return new Utf8Entry(readString(in, length));
|
||||
}
|
||||
|
||||
protected String readString(DataInputStream in, short length) {
|
||||
try {
|
||||
byte[] bytes = in.readNBytes(length);
|
||||
return new String(bytes, StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
protected long readLong(DataInputStream in) {
|
||||
try {
|
||||
return in.readLong();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected double readDouble(DataInputStream in) {
|
||||
try {
|
||||
return in.readDouble();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected short readShort(DataInputStream in) {
|
||||
try {
|
||||
return in.readShort();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected int readUnsignedShort(DataInputStream in) {
|
||||
try {
|
||||
return in.readUnsignedShort();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected int readInt(DataInputStream in) {
|
||||
try {
|
||||
return in.readInt();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected byte readByte(DataInputStream in) {
|
||||
try {
|
||||
return in.readByte();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void expect(DataInputStream in, int expected) {
|
||||
try {
|
||||
int i = in.readInt();
|
||||
if (i != expected) {
|
||||
throw new IllegalStateException("class file not valid");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected long skip(InputStream in, long bytecount) {
|
||||
try {
|
||||
return in.skip(bytecount);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -41,4 +41,6 @@ public class Field {
|
|||
", type='" + type + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
36
src/main/java/nl/sander/jsontoy2/java/Info.java
Normal file
36
src/main/java/nl/sander/jsontoy2/java/Info.java
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
package nl.sander.jsontoy2.java;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class Info {
|
||||
private final int accesFlags;
|
||||
private final int nameIndex;
|
||||
private final int descriptorIndex;
|
||||
private final int attributesCount;
|
||||
private final Set<AttributeInfo> attributeInfos = new HashSet<>();
|
||||
|
||||
|
||||
public Info(int accesFlags, int nameIndex, int descriptorIndex, int attributesCount) {
|
||||
this.accesFlags = accesFlags;
|
||||
this.nameIndex = nameIndex;
|
||||
this.descriptorIndex = descriptorIndex;
|
||||
this.attributesCount = attributesCount;
|
||||
}
|
||||
|
||||
public int getNameIndex() {
|
||||
return nameIndex;
|
||||
}
|
||||
|
||||
public int getDescriptorIndex() {
|
||||
return descriptorIndex;
|
||||
}
|
||||
|
||||
void add(AttributeInfo attributeInfo) {
|
||||
attributeInfos.add(attributeInfo);
|
||||
}
|
||||
|
||||
public int getAttributesCount() {
|
||||
return attributesCount;
|
||||
}
|
||||
}
|
||||
44
src/main/java/nl/sander/jsontoy2/java/Method.java
Normal file
44
src/main/java/nl/sander/jsontoy2/java/Method.java
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
package nl.sander.jsontoy2.java;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class Method {
|
||||
|
||||
private final String name;
|
||||
private final String type;
|
||||
|
||||
public Method(String name, String type) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Method field = (Method) o;
|
||||
return name.equals(field.name) &&
|
||||
type.equals(field.type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Method{" +
|
||||
"name='" + name + '\'' +
|
||||
", type='" + type + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
package nl.sander.jsontoy2.java.constantpool;
|
||||
|
||||
public class ClassEntry extends ConstantPoolEntry {
|
||||
private final short nameIndex;
|
||||
private final int nameIndex;
|
||||
|
||||
public ClassEntry(short nameIndex) {
|
||||
public ClassEntry(int nameIndex) {
|
||||
this.nameIndex = nameIndex;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
package nl.sander.jsontoy2.java.constantpool;
|
||||
|
||||
public class InterfaceMethodRefEntry extends ConstantPoolEntry {
|
||||
private final short classIndex;
|
||||
private final short nameAndTypeIndex;
|
||||
private final int classIndex;
|
||||
private final int nameAndTypeIndex;
|
||||
|
||||
public InterfaceMethodRefEntry(short classIndex, short nameAndTypeIndex) {
|
||||
public InterfaceMethodRefEntry(int classIndex, int nameAndTypeIndex) {
|
||||
this.classIndex = classIndex;
|
||||
this.nameAndTypeIndex = nameAndTypeIndex;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
package nl.sander.jsontoy2.java.constantpool;
|
||||
|
||||
public class InvokeDynamicEntry extends ConstantPoolEntry {
|
||||
private final short bootstrapMethodAttrIndex;
|
||||
private final short nameAndTypeIndex;
|
||||
private final int bootstrapMethodAttrIndex;
|
||||
private final int nameAndTypeIndex;
|
||||
|
||||
public InvokeDynamicEntry(short bootstrapMethodAttrIndex, short nameAndTypeIndex) {
|
||||
public InvokeDynamicEntry(int bootstrapMethodAttrIndex, int nameAndTypeIndex) {
|
||||
this.bootstrapMethodAttrIndex = bootstrapMethodAttrIndex;
|
||||
this.nameAndTypeIndex = nameAndTypeIndex;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
package nl.sander.jsontoy2.java.constantpool;
|
||||
|
||||
public class MethodHandleEntry extends ConstantPoolEntry {
|
||||
private final short referenceKind;
|
||||
private final short referenceIndex;
|
||||
private final int referenceKind;
|
||||
private final int referenceIndex;
|
||||
|
||||
public MethodHandleEntry(short referenceKind, short referenceIndex) {
|
||||
public MethodHandleEntry(int referenceKind, int referenceIndex) {
|
||||
this.referenceKind = referenceKind;
|
||||
this.referenceIndex = referenceIndex;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,18 @@
|
|||
package nl.sander.jsontoy2.java.constantpool;
|
||||
|
||||
public class MethodRefEntry extends ConstantPoolEntry {
|
||||
private final short classIndex;
|
||||
private final short nameAndTypeIndex;
|
||||
private final int classIndex;
|
||||
private final int nameAndTypeIndex;
|
||||
|
||||
public MethodRefEntry(short classIndex, short nameAndTypeIndex) {
|
||||
public MethodRefEntry(int classIndex, int nameAndTypeIndex) {
|
||||
this.classIndex = classIndex;
|
||||
this.nameAndTypeIndex = nameAndTypeIndex;
|
||||
}
|
||||
|
||||
public int getNameAndTypeIndex() {
|
||||
return nameAndTypeIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MethodRefEntry{" +
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
package nl.sander.jsontoy2.java.constantpool;
|
||||
|
||||
public class MethodTypeEntry extends ConstantPoolEntry {
|
||||
private final short descriptorIndex;
|
||||
private final int descriptorIndex;
|
||||
|
||||
public MethodTypeEntry(short descriptorIndex) {
|
||||
public MethodTypeEntry(int descriptorIndex) {
|
||||
this.descriptorIndex = descriptorIndex;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
package nl.sander.jsontoy2.java.constantpool;
|
||||
|
||||
public class NameAndTypeEntry extends ConstantPoolEntry {
|
||||
private final short nameIndex;
|
||||
private final short typeIndex;
|
||||
private final int nameIndex;
|
||||
private final int typeIndex;
|
||||
|
||||
public NameAndTypeEntry(short nameIndex, short typeIndex) {
|
||||
public NameAndTypeEntry(int nameIndex, int typeIndex) {
|
||||
this.nameIndex = nameIndex;
|
||||
this.typeIndex = typeIndex;
|
||||
}
|
||||
|
||||
public short getNameIndex() {
|
||||
public int getNameIndex() {
|
||||
return nameIndex;
|
||||
}
|
||||
|
||||
public short getTypeIndex() {
|
||||
public int getTypeIndex() {
|
||||
return typeIndex;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
package nl.sander.jsontoy2.java.constantpool;
|
||||
|
||||
public class StringEntry extends ConstantPoolEntry {
|
||||
private final short utf8Index;
|
||||
private final int utf8Index;
|
||||
|
||||
public StringEntry(short utf8Index) {
|
||||
public StringEntry(int utf8Index) {
|
||||
this.utf8Index = utf8Index;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,18 +6,14 @@ import java.util.Set;
|
|||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class ClassParserTest {
|
||||
public class ClassReaderTest {
|
||||
|
||||
private int field;
|
||||
public int field;
|
||||
|
||||
@Test
|
||||
public void testReadClass() {
|
||||
ClassObject<ClassParserTest> object = new ClassParser().parse(ClassParserTest.class);
|
||||
ClassObject<ClassReaderTest> object = new ClassReader().parse(ClassReaderTest.class);
|
||||
assertEquals(Set.of(new Field("field", "I")), object.getFields());
|
||||
}
|
||||
|
||||
// if not included, field is not in the compiled code.
|
||||
public int getField() {
|
||||
return field;
|
||||
assertEquals(Set.of(new Method("<init>", "()V"), new Method("testReadClass", "()V")), object.getMethods());
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue