diff --git a/src/main/java/nl/sander/jsontoy2/JsonReader.java b/src/main/java/nl/sander/jsontoy2/JsonReader.java index 6179a0d..8dedf14 100644 --- a/src/main/java/nl/sander/jsontoy2/JsonReader.java +++ b/src/main/java/nl/sander/jsontoy2/JsonReader.java @@ -43,7 +43,7 @@ public class JsonReader { * array => List */ public static Object read(InputStream inputStream) { - InputStream in = ensureBuffered(inputStream); + final InputStream in = ensureBuffered(inputStream); try (Parser parser = getParser(in)) { return read(parser); } diff --git a/src/main/java/nl/sander/jsontoy2/Parser.java b/src/main/java/nl/sander/jsontoy2/Parser.java index a4871d2..de5f77b 100644 --- a/src/main/java/nl/sander/jsontoy2/Parser.java +++ b/src/main/java/nl/sander/jsontoy2/Parser.java @@ -37,37 +37,37 @@ public class Parser extends Lexer { } public Integer parseInteger() { - String value = parseNumber(); + final String value = parseNumber(); return Double.valueOf(value).intValue(); } public Long parseLong() { - String value = parseNumber(); + final String value = parseNumber(); return Long.parseLong(value); } public Float parseFloat() { - String value = parseNumber(); + final String value = parseNumber(); return Float.parseFloat(value); } public Double parseDouble() { - String value = parseNumber(); + final String value = parseNumber(); return Double.parseDouble(value); } public Short parseShort() { - String value = parseNumber(); + final String value = parseNumber(); return Short.parseShort(value); } public Byte parseByte() { - String value = parseNumber(); + final String value = parseNumber(); return Byte.parseByte(value); } public Character parseCharacter() { - String string = parseString(); + final String string = parseString(); return string.charAt(0); } @@ -78,7 +78,7 @@ public class Parser extends Lexer { advance(); } - String maybeBoolean = characterBuffer.toString(); + final String maybeBoolean = characterBuffer.toString(); boolean returnValue; if ((returnValue = maybeBoolean.equals("true")) || maybeBoolean.equals("false")) { return returnValue; @@ -109,10 +109,10 @@ public class Parser extends Lexer { if (current != '[') { throw new JsonParseException("no list found"); } - List list = new ArrayList<>(); + final List list = new ArrayList<>(); advance(); while (current != -1 && current != ']') { - Maybe maybeValue = parseValue(); + final Maybe maybeValue = parseValue(); if (!maybeValue.isPresent()) { break; } else { @@ -125,7 +125,7 @@ public class Parser extends Lexer { } public Map parseObject() { - HashMap map = new HashMap<>(); + final HashMap map = new HashMap<>(); skipWhitespace(); if (current != '{') { throw new JsonParseException("no map found"); @@ -134,7 +134,7 @@ public class Parser extends Lexer { while (current != -1 && current != '}') { skipWhitespace(); if (current == '"') { - String key = parseString(); + final String key = parseString(); skipWhitespace(); if (current == ':') { advance(); @@ -142,7 +142,7 @@ public class Parser extends Lexer { throw new JsonParseException("expected colon"); } skipWhitespace(); - Maybe maybeValue = parseValue(); + final Maybe maybeValue = parseValue(); maybeValue.ifPresent(value -> map.put(key, value)); } advance(); @@ -152,7 +152,7 @@ public class Parser extends Lexer { } public Object parseAny() { - Maybe maybe = parseValue(); + final Maybe maybe = parseValue(); if (maybe.isPresent()) { return maybe.get(); } else { @@ -161,7 +161,7 @@ public class Parser extends Lexer { } private Maybe parseValue() { - Object value; + final Object value; skipWhitespace(); switch (current) { case ']': @@ -251,8 +251,8 @@ public class Parser extends Lexer { } private void parseEncoded() { - StringBuilder buf = new StringBuilder(); - char codePoint = parseCodePoint(); + final StringBuilder buf = new StringBuilder(); + final char codePoint = parseCodePoint(); buf.append(codePoint); if (Character.isHighSurrogate(codePoint)) { expect(() -> new JsonParseException("Invalid unicode codepoint at line " + linecount), '\\', 'u'); diff --git a/src/main/java/nl/sander/jsontoy2/java/ClassObject.java b/src/main/java/nl/sander/jsontoy2/java/ClassObject.java index c2cb03b..3c71ab5 100644 --- a/src/main/java/nl/sander/jsontoy2/java/ClassObject.java +++ b/src/main/java/nl/sander/jsontoy2/java/ClassObject.java @@ -7,12 +7,20 @@ import java.util.Arrays; import java.util.Set; import java.util.stream.Collectors; +/** + * Contains info from parsed bytecode + */ +public class ClassObject { -public class ClassObject { + private final ConstantPoolEntry[] constantPool; + private final Info[] fieldInfos; + private final Info[] methodInfos; - private ConstantPoolEntry[] constantPool; - private Info[] fieldInfos; - private Info[] methodInfos; + private ClassObject(ConstantPoolEntry[] constantPool, Info[] fieldInfos, Info[] methodInfos) { + this.constantPool = constantPool; + this.fieldInfos = fieldInfos; + this.methodInfos = methodInfos; + } private String getUtf8(int index) { return ((Utf8Entry) constantPool[index - 1]).getUtf8(); @@ -41,41 +49,44 @@ public class ClassObject { public static class Builder { - private final ClassObject classObject = new ClassObject<>(); private int constantPoolIndex = 0; private int fieldInfoIndex = 0; private int methodInfoIndex = 0; - public ClassObject build() { - return classObject; + private ConstantPoolEntry[] constantPool; + private Info[] fieldInfos; + private Info[] methodInfos; + + public ClassObject build() { + return new ClassObject(constantPool, fieldInfos, methodInfos); } public Builder constantPoolCount(int constantPoolCount) { - classObject.constantPool = new ConstantPoolEntry[constantPoolCount - 1]; + constantPool = new ConstantPoolEntry[constantPoolCount - 1]; return this; } void constantPoolEntry(ConstantPoolEntry entry) { - classObject.constantPool[constantPoolIndex++] = entry; + constantPool[constantPoolIndex++] = entry; } public Builder fieldInfoCount(int fieldInfoCount) { - classObject.fieldInfos = new Info[fieldInfoCount]; + fieldInfos = new Info[fieldInfoCount]; return this; } public Builder fieldInfo(Info fieldInfo) { - classObject.fieldInfos[fieldInfoIndex++] = fieldInfo; + fieldInfos[fieldInfoIndex++] = fieldInfo; return this; } public Builder methodInfoCount(int methodInfoCount) { - classObject.methodInfos = new Info[methodInfoCount]; + methodInfos = new Info[methodInfoCount]; return this; } public Builder methodInfo(Info methodInfo) { - classObject.methodInfos[methodInfoIndex++] = methodInfo; + methodInfos[methodInfoIndex++] = methodInfo; return this; } } diff --git a/src/main/java/nl/sander/jsontoy2/java/ClassReader.java b/src/main/java/nl/sander/jsontoy2/java/ClassReader.java index cd9a6bc..0d40ce9 100644 --- a/src/main/java/nl/sander/jsontoy2/java/ClassReader.java +++ b/src/main/java/nl/sander/jsontoy2/java/ClassReader.java @@ -8,8 +8,8 @@ import java.io.IOException; public class ClassReader extends DataReader { - public ClassObject parse(Class type) { - DataInputStream in = new DataInputStream(new BufferedInputStream(type.getResourceAsStream(getResourceName(type)))); + public ClassObject parse(Class type) { + final DataInputStream in = new DataInputStream(new BufferedInputStream(type.getResourceAsStream(getResourceName(type)))); expect(in, 0xCAFEBABE); ClassObject.Builder builder = new ClassObject.Builder<>(); @@ -19,7 +19,7 @@ public class ClassReader extends DataReader { readConstantPool(in, builder); skip(in, 6); // u2 access_flags, u2 this_class, u2 super_class - int interfacesCount = readU16(in); + final int interfacesCount = readUnsignedShort(in); skip(in, interfacesCount * 2); // interfaces[u2;] readFields(in, builder); @@ -29,7 +29,7 @@ public class ClassReader extends DataReader { } private void readConstantPool(DataInputStream in, ClassObject.Builder builder) { - int constantPoolCount = readU16(in); + final int constantPoolCount = readUnsignedShort(in); builder.constantPoolCount(constantPoolCount); for (int i = 1; i < constantPoolCount; i++) { builder.constantPoolEntry(readConstantPoolEntry(in)); @@ -37,7 +37,7 @@ public class ClassReader extends DataReader { } private void readFields(DataInputStream in, ClassObject.Builder builder) { - int fieldInfoCount = readU16(in); + final int fieldInfoCount = readUnsignedShort(in); builder.fieldInfoCount(fieldInfoCount); for (int i = 0; i < fieldInfoCount; i++) { builder.fieldInfo(readField(in)); @@ -45,7 +45,7 @@ public class ClassReader extends DataReader { } private void readMethods(DataInputStream in, ClassObject.Builder builder) { - int methodInfoCount = readU16(in); + final int methodInfoCount = readUnsignedShort(in); builder.methodInfoCount(methodInfoCount); for (int i = 0; i < methodInfoCount; i++) { builder.methodInfo(readMethod(in)); @@ -53,7 +53,7 @@ public class ClassReader extends DataReader { } private Info readField(DataInputStream in) { - Info fieldInfo = new Info(readU16(in), readU16(in), readU16(in), readU16(in)); + final Info fieldInfo = new Info(readUnsignedShort(in), readUnsignedShort(in), readUnsignedShort(in), readUnsignedShort(in)); for (int i = 0; i < fieldInfo.getAttributesCount(); i++) { fieldInfo.add(readAttribute(in)); } @@ -62,7 +62,7 @@ public class ClassReader extends DataReader { } private Info readMethod(DataInputStream in) { - Info methodInfo = new Info(readU16(in), readU16(in), readU16(in), readU16(in)); + final Info methodInfo = new Info(readUnsignedShort(in), readUnsignedShort(in), readUnsignedShort(in), readUnsignedShort(in)); for (int i = 0; i < methodInfo.getAttributesCount(); i++) { methodInfo.add(readAttribute(in)); } @@ -71,9 +71,9 @@ public class ClassReader extends DataReader { } private AttributeInfo readAttribute(DataInputStream in) { - int attributeNameIndex = readU16(in); - int attributeLength = readS32(in); - byte[] info; + final int attributeNameIndex = readUnsignedShort(in); + final int attributeLength = readS32(in); + final byte[] info; if (attributeLength > 0) { info = new byte[attributeLength]; try { @@ -87,32 +87,32 @@ public class ClassReader extends DataReader { return new AttributeInfo(attributeNameIndex, info); } - private ConstantPoolEntry readConstantPoolEntry(DataInputStream in) { - byte tag = readByte(in); + private ConstantPoolEntry readConstantPoolEntry(DataInputStream in) { + final byte tag = readByte(in); switch (tag) { - case 1: return readUtf8Entry(in); + case 1: return new Utf8Entry(readString(in, readUnsignedShort(in))); case 2: throw new IllegalStateException("2: invalid classpool tag"); case 3: return new IntEntry(readS32(in)); case 4: return new FloatEntry(readF32(in)); case 5: return new LongEntry(readS64(in)); case 6: return new DoubleEntry(readF64(in)); - case 7: return new ClassEntry(readU16(in)); - case 8: return new StringEntry(readU16(in)); - case 9: return new FieldRefEntry(readU16(in), readU16(in)); - case 10: return new MethodRefEntry(readU16(in), readU16(in)); - case 11: return new InterfaceMethodRefEntry(readU16(in), readU16(in)); - case 12: return new NameAndTypeEntry(readU16(in), readU16(in)); - case 15: return new MethodHandleEntry(readU16(in), readU16(in)); - case 16: return new MethodTypeEntry(readU16(in)); - case 18: return new InvokeDynamicEntry(readU16(in), readU16(in)); - case 19: return new ModuleEntry(readU16(in)); - case 20: return new PackageEntry(readU16(in)); + case 7: return new ClassEntry(readUnsignedShort(in)); + case 8: return new StringEntry(readUnsignedShort(in)); + case 9: return new FieldRefEntry(readUnsignedShort(in), readUnsignedShort(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)); + case 19: return new ModuleEntry(readUnsignedShort(in)); + case 20: return new PackageEntry(readUnsignedShort(in)); default: throw new IllegalStateException("invalid classpool"); } } protected String getResourceName(Class type) { - StringBuilder typeName = new StringBuilder("/" + type.getName()); + final StringBuilder typeName = new StringBuilder("/" + type.getName()); for (int i = 0; i < typeName.length(); i++) { if (typeName.charAt(i) == '.') { diff --git a/src/main/java/nl/sander/jsontoy2/java/DataReader.java b/src/main/java/nl/sander/jsontoy2/java/DataReader.java index b00a125..218fe94 100644 --- a/src/main/java/nl/sander/jsontoy2/java/DataReader.java +++ b/src/main/java/nl/sander/jsontoy2/java/DataReader.java @@ -1,12 +1,13 @@ 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; +/** + * basic IO operations with runtime exceptions + */ public class DataReader { protected long readS64(DataInputStream in) { @@ -33,7 +34,7 @@ public class DataReader { } } - protected int readU16(DataInputStream in) { + protected int readUnsignedShort(DataInputStream in) { try { return in.readUnsignedShort(); } catch (IOException e) { @@ -49,11 +50,6 @@ public class DataReader { } } - protected Utf8Entry readUtf8Entry(DataInputStream in) { - int length = readU16(in); - return new Utf8Entry(readString(in, length)); - } - protected String readString(DataInputStream in, int length) { try { byte[] bytes = in.readNBytes(length); diff --git a/src/test/java/nl/sander/jsontoy2/java/ClassReaderTest.java b/src/test/java/nl/sander/jsontoy2/java/ClassReaderTest.java index e6108a8..4d69ef8 100644 --- a/src/test/java/nl/sander/jsontoy2/java/ClassReaderTest.java +++ b/src/test/java/nl/sander/jsontoy2/java/ClassReaderTest.java @@ -8,11 +8,12 @@ import static org.junit.jupiter.api.Assertions.assertEquals; public class ClassReaderTest { + //part of the test public int field; @Test public void testReadClass() { - ClassObject object = new ClassReader().parse(ClassReaderTest.class); + ClassObject object = new ClassReader().parse(ClassReaderTest.class); assertEquals(Set.of(new Field("field", "I")), object.getFields()); assertEquals(Set.of(new Method("", "()V"), new Method("testReadClass", "()V")), object.getMethods()); }