Skip to content

Commit 894d945

Browse files
committed
added support of superclasses for generated internal structures
1 parent 9c085fe commit 894d945

File tree

3 files changed

+129
-22
lines changed

3 files changed

+129
-22
lines changed

jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/conversion/JBBPToJava6Converter.java

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -254,9 +254,11 @@ public void visitEnd() {
254254
this.builder.superClass,
255255
this.builder.mainClassImplements,
256256
this.builder.mapSubClassesInterfaces,
257+
this.builder.mapSubClassesSuperclasses,
257258
this.specialSection.toString(),
258259
specialMethodsText.length() == 0 ? null : specialMethodsText,
259-
this.builder.mainClassCustomText
260+
this.builder.mainClassCustomText,
261+
true
260262
);
261263

262264
this.result = buffer.toString();
@@ -272,18 +274,27 @@ public void visitStructureStart(final int offsetInCompiledBlock, final JBBPNamed
272274

273275
final String fieldModifier = makeModifier(nullableNameFieldInfo);
274276

277+
final String toType;
278+
if (this.builder.generateFields) {
279+
toType = "";
280+
} else {
281+
toType = '('+structBaseTypeName+')';
282+
}
283+
275284
final String structType;
276285
if (nullableArraySize == null) {
277286
structType = structBaseTypeName;
278287
if (this.builder.generateFields) {
279288
this.getCurrentStruct().getFields().indent().print(fieldModifier).printf(" %s %s;", structType, structName).println();
280289
}
290+
281291
processSkipRemainingFlag();
282292
processSkipRemainingFlagForWriting("this." + structName);
293+
283294
this.getCurrentStruct().getReadFunc().indent()
284295
.printf("if ( this.%1$s == null) { this.%1$s = new %2$s(%3$s);}", structName, structType, this.structStack.size() == 1 ? "this" : "this." + NAME_ROOT_STRUCT)
285-
.printf(" this.%s.read(%s);%n", structName, NAME_INPUT_STREAM);
286-
this.getCurrentStruct().getWriteFunc().indent().print(structName).println(".write(Out);");
296+
.printf(" %s.read(%s);%n", toType.length() == 0 ? "this." + structName : '('+toType+ "this." + structName+')', NAME_INPUT_STREAM);
297+
this.getCurrentStruct().getWriteFunc().indent().print(toType.length() == 0 ? structName : '(' +toType + structName + ')').println(".write(Out);");
287298
} else {
288299
structType = structBaseTypeName + " []";
289300
if (this.builder.generateFields) {
@@ -293,13 +304,18 @@ public void visitStructureStart(final int offsetInCompiledBlock, final JBBPNamed
293304
processSkipRemainingFlagForWriting("this." + structName);
294305
if ("-1".equals(arraySizeIn)) {
295306
this.getCurrentStruct().getReadFunc().indent()
296-
.printf("List<%3$s> __%1$s_tmplst__ = new ArrayList<%3$s>(); while (%5$s.hasAvailableData()){ __%1$s_tmplst__.add(new %3$s(%4$s).read(%5$s));} this.%1$s = __%1$s_tmplst__.toArray(new %3$s[__%1$s_tmplst__.size()]);__%1$s_tmplst__ = null;%n", structName, arraySizeIn, structBaseTypeName, (this.structStack.size() == 1 ? "this" : NAME_ROOT_STRUCT), NAME_INPUT_STREAM);
297-
this.getCurrentStruct().getWriteFunc().indent().printf("for (int I=0;I<this.%1$s.length;I++){ this.%1$s[I].write(%2$s); }%n", structName, NAME_OUTPUT_STREAM);
307+
.printf("List<%3$s> __%1$s_tmplst__ = new ArrayList<%3$s>(); while (%5$s.hasAvailableData()){ __%1$s_tmplst__.add(new %3$s(%4$s).read(%5$s));} this.%1$s = __%1$s_tmplst__.toArray(new %3$s[__%1$s_tmplst__.size()]);__%1$s_tmplst__ = null;%n",
308+
structName,
309+
arraySizeIn,
310+
structBaseTypeName,
311+
(this.structStack.size() == 1 ? "this" : NAME_ROOT_STRUCT),
312+
NAME_INPUT_STREAM);
313+
this.getCurrentStruct().getWriteFunc().indent().printf("for (int I=0;I<this.%1$s.length;I++){ %2$s.write(%3$s); }%n", structName, toType.length() == 0 ? "this."+structName + "[I]" : '(' + toType +"this."+structName + "[I])", NAME_OUTPUT_STREAM);
298314
} else {
299315
this.getCurrentStruct().getReadFunc().indent()
300316
.printf("if (this.%1$s == null || this.%1$s.length != %2$s){ this.%1$s = new %3$s[%2$s]; for(int I=0;I<%2$s;I++){ this.%1$s[I] = new %3$s(%4$s);}}", structName, arraySizeIn, structBaseTypeName, (this.structStack.size() == 1 ? "this" : "this." + NAME_ROOT_STRUCT))
301-
.printf("for (int I=0;I<%2$s;I++){ this.%1$s[I].read(%3$s); }%n", structName, arraySizeIn, NAME_INPUT_STREAM);
302-
this.getCurrentStruct().getWriteFunc().indent().printf("for (int I=0;I<%2$s;I++){ this.%1$s[I].write(%3$s); }", structName, arraySizeOut, NAME_OUTPUT_STREAM);
317+
.printf("for (int I=0;I<%2$s;I++){ this.%1$s[I].read(%3$s); }%n", toType + structName, arraySizeIn, NAME_INPUT_STREAM);
318+
this.getCurrentStruct().getWriteFunc().indent().printf("for (int I=0;I<%2$s;I++){ this.%1$s[I].write(%3$s); }", toType + structName, arraySizeOut, NAME_OUTPUT_STREAM);
303319
}
304320
}
305321

@@ -951,6 +967,10 @@ public static final class Builder {
951967
* Interfaces to be implemented by generated subclasses, also getters return the interface type.
952968
*/
953969
private final Map<String, String> mapSubClassesInterfaces = new HashMap<String, String>();
970+
/**
971+
* Superclasses to be extended by generated subclasses.
972+
*/
973+
private final Map<String, String> mapSubClassesSuperclasses = new HashMap<String, String>();
954974
/**
955975
* The Package name for the result class.
956976
*/
@@ -1021,6 +1041,22 @@ public Builder setMapSubClassesInterfaces(final Map<String, String> mapClassName
10211041
return this;
10221042
}
10231043

1044+
/**
1045+
* Add superclasses to classes generated for inside structures, a structure class will extend mapped class.
1046+
*
1047+
* @param mapClassNameToSuperclasses map with structure path as the key and the interface name as value, it can be null. <b>Names of structures should be in the lower case form amd dot separated for their hierarchy. (example: "a.b.c")</b>
1048+
* @return the builder instance, must not be null
1049+
* @since 1.4.0
1050+
*/
1051+
public Builder setMapSubClassesSuperclasses(final Map<String, String> mapClassNameToSuperclasses) {
1052+
assertNonLocked();
1053+
this.mapSubClassesSuperclasses.clear();
1054+
if (mapClassNameToSuperclasses != null) {
1055+
this.mapSubClassesSuperclasses.putAll(mapClassNameToSuperclasses);
1056+
}
1057+
return this;
1058+
}
1059+
10241060
/**
10251061
* Set custom text, the text will be added into the end of the result class.
10261062
*
@@ -1203,7 +1239,17 @@ Struct findRoot() {
12031239
return this.parent.findRoot();
12041240
}
12051241

1206-
void write(final JavaSrcTextBuffer buffer, final String extraModifier, final String superClass, final Set<String> implementedInterfaces, final Map<String, String> mapStructInterfaces, final String commonSectionText, final String specialMethods, final String customText) {
1242+
void write(
1243+
final JavaSrcTextBuffer buffer,
1244+
final String extraModifier,
1245+
final String superClass,
1246+
final Set<String> implementedInterfaces,
1247+
final Map<String, String> mapStructInterfaces,
1248+
final Map<String, String> mapStructSuperclasses,
1249+
final String commonSectionText,
1250+
final String specialMethods,
1251+
final String customText,
1252+
final boolean useSuperclassForReadWrite) {
12071253
final String interfaceForGetSet = mapStructInterfaces == null ? null : mapStructInterfaces.get(this.getPath());
12081254

12091255
buffer.indent().printf(
@@ -1221,7 +1267,7 @@ void write(final JavaSrcTextBuffer buffer, final String extraModifier, final Str
12211267
}
12221268

12231269
for (final Struct c : this.children) {
1224-
c.write(buffer, null, null, null, mapStructInterfaces, null, null, null);
1270+
c.write(buffer, null, mapStructSuperclasses.get(c.getPath()), null, mapStructInterfaces, mapStructSuperclasses, null, null, null, false);
12251271
}
12261272
buffer.println();
12271273

@@ -1245,7 +1291,7 @@ void write(final JavaSrcTextBuffer buffer, final String extraModifier, final Str
12451291

12461292
buffer.println();
12471293

1248-
buffer.indent().printf("public %s read(final JBBPBitInputStream In) throws IOException {%n", superClass == null ? this.className : superClass);
1294+
buffer.indent().printf("public %s read(final JBBPBitInputStream In) throws IOException {%n", useSuperclassForReadWrite && superClass != null ? superClass : this.className);
12491295
buffer.incIndent();
12501296
buffer.printLinesWithIndent(this.readFunc.toString());
12511297
buffer.indent().println("return this;");
@@ -1254,7 +1300,7 @@ void write(final JavaSrcTextBuffer buffer, final String extraModifier, final Str
12541300

12551301
buffer.println();
12561302

1257-
buffer.indent().printf("public %s write(final JBBPBitOutputStream Out) throws IOException {%n", superClass == null ? this.className : superClass);
1303+
buffer.indent().printf("public %s write(final JBBPBitOutputStream Out) throws IOException {%n", useSuperclassForReadWrite && superClass != null ? superClass : this.className);
12581304
buffer.incIndent();
12591305
buffer.printLinesWithIndent(this.writeFunc.toString());
12601306
buffer.indent().println("return this;");

jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/conversion/JBBPToJBBPToJava6ConverterCompilationTest.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,17 @@ public void testForceAbstract() throws Exception {
5959
@Test
6060
public void testMapSubstructToInterface() throws Exception {
6161
final JBBPParser parser = JBBPParser.prepare("a { b { c [_] { byte d;}} }");
62-
final String text = JBBPToJava6Converter.makeBuilder(parser).setMainClassName(CLASS_NAME).setAddGettersSetters(true).setMapSubClassesInterfaces(makeMap("a.b", "com.igormaznitsa.Impl", "a.b.c", "com.igormaznitsa.Impl2")).build().convert();
62+
final String text = JBBPToJava6Converter.makeBuilder(parser)
63+
.setMainClassName(CLASS_NAME)
64+
.setAddGettersSetters(true)
65+
.setMapSubClassesInterfaces(
66+
makeMap(
67+
"a.b","com.igormaznitsa.Impl",
68+
"a.b.c", "com.igormaznitsa.Impl2"
69+
)
70+
)
71+
.build()
72+
.convert();
6373
assertTrue(text.contains("public static class B implements com.igormaznitsa.Impl"));
6474
assertTrue(text.contains("public static class C implements com.igormaznitsa.Impl2"));
6575
assertTrue(text.contains("public com.igormaznitsa.Impl getB() { return this.b;}"));

jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/conversion/JBBPToJava6ConverterReadWriteTest.java

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import java.io.ByteArrayOutputStream;
3939
import java.io.IOException;
4040
import java.io.InputStream;
41+
import java.util.Collections;
4142
import java.util.HashMap;
4243
import java.util.Map;
4344

@@ -62,18 +63,65 @@ private byte[] loadResource(final String name) throws Exception {
6263
}
6364

6465
public static abstract class TestSuperclass {
65-
protected String str;
66-
protected String[] strarr;
67-
protected float flt;
68-
protected float[] fltarr;
69-
protected double dbl;
70-
protected double[] dblarr;
66+
public String str;
67+
public String[] strarr;
68+
public float flt;
69+
public float[] fltarr;
70+
public double dbl;
71+
public double[] dblarr;
72+
public char len;
73+
74+
public static abstract class Ins {
75+
public byte[] a;
76+
public byte b;
77+
public byte c;
78+
79+
public static abstract class InsIns {
80+
public byte a;
81+
}
82+
83+
public InsIns insins;
84+
}
85+
86+
public Ins[] ins;
7187
}
7288

7389
@Test
7490
public void testReadWrite_ExtendsSuperClassAndUseItsFields() throws Exception {
75-
final JBBPParser parser = JBBPParser.prepare("stringj str; stringj [2] strarr; floatj flt; floatj [2] fltarr; doublej dbl; doublej [2] dblarr;");
76-
final String text = JBBPToJava6Converter.makeBuilder(parser).setMainClassName(CLASS_NAME).setMainClassPackage(PACKAGE_NAME).disableGenerateFields().setSuperClass(TestSuperclass.class.getCanonicalName()).setAddGettersSetters(true).build().convert();
91+
final JBBPParser parser = JBBPParser.prepare(
92+
"stringj str;"
93+
+ "stringj [2] strarr;"
94+
+ "floatj flt;"
95+
+ "floatj [2] fltarr;"
96+
+ "doublej dbl;"
97+
+ "doublej [2] dblarr;"
98+
+ "ubyte len;"
99+
+ "ins [_] {"
100+
+ " byte [len] a;"
101+
+ " byte b;"
102+
+ " byte c;"
103+
+ " insins {"
104+
+ " byte a;"
105+
+ " }"
106+
+ "}"
107+
);
108+
109+
this.printGeneratedClassText = true;
110+
111+
final Map<String,String> superclasses = new HashMap<String, String>();
112+
superclasses.put("ins",TestSuperclass.Ins.class.getCanonicalName());
113+
superclasses.put("ins.insins",TestSuperclass.Ins.InsIns.class.getCanonicalName());
114+
115+
final String text = JBBPToJava6Converter.makeBuilder(parser)
116+
.setMainClassName(CLASS_NAME)
117+
.setMainClassPackage(PACKAGE_NAME)
118+
.disableGenerateFields()
119+
.setSuperClass(TestSuperclass.class.getCanonicalName())
120+
.setMapSubClassesSuperclasses(superclasses)
121+
.setAddGettersSetters(false)
122+
.build()
123+
.convert();
124+
77125
final String fullClassName = PACKAGE_NAME + '.' + CLASS_NAME;
78126
final ClassLoader classLoader = saveAndCompile(new JavaClassContent(fullClassName, text));
79127

@@ -86,7 +134,10 @@ public void testReadWrite_ExtendsSuperClassAndUseItsFields() throws Exception {
86134
1, 2, 3, 4,
87135
5, 6, 7, 8, 9, 10, 11, 12,
88136
1, 2, 3, 4, 5, 6, 7, 8,
89-
9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24
137+
9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
138+
2,
139+
1,2,
140+
3,4,5
90141
});
91142

92143
final TestSuperclass parsed = (TestSuperclass) instance;
@@ -200,7 +251,7 @@ public void testReadWite_Val_CalculatedLength() throws Exception {
200251

201252
callRead(instance, etalon.clone());
202253

203-
assertArrayEquals(new byte[]{33,44}, getField(instance, "data", byte[].class));
254+
assertArrayEquals(new byte[] {33, 44}, getField(instance, "data", byte[].class));
204255
assertArrayEquals(etalon, callWrite(instance));
205256
}
206257

0 commit comments

Comments
 (0)