Last active
June 25, 2016 13:11
-
-
Save raydac/28d770307bd33683aa17ea3c39d5e2c4 to your computer and use it in GitHub Desktop.
Function to generate [JBBP DSL script](https://github.com/raydac/java-binary-block-parser) from a class contains fields marked by `@Bin` annotations
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Generates <a href="https://github.com/raydac/java-binary-block-parser">JBBP DSL script</a> from class @BIN annotated fields. Extra field of @BIN annotation is used as expression for array length if the text starts with 'expr:' | |
* <p>Example code: | |
* <pre>{@code | |
* public static class Chunk { | |
* @Bin(outOrder = 1, type = BinType.INT) | |
* int length; | |
* @Bin(outOrder = 2, type = BinType.INT) | |
* int type; | |
* @Bin(outOrder = 3, type = BinType.BYTE_ARRAY, extra = "expr:length") | |
* byte[] data; | |
* @Bin(outOrder = 4, type = BinType.INT) | |
* int crc; | |
* } | |
* | |
* public static class PNGFormat { | |
* @Bin(outOrder = 1, type = BinType.LONG) | |
* long header; | |
* @Bin(outOrder = 2, type = BinType.STRUCT_ARRAY) | |
* Chunk[] chunks; | |
* } | |
* | |
* public static void main(String... args) throws Exception { | |
* System.out.println(class2jbbp(PNGFormat.class)); | |
* } | |
* }</pre> | |
* </p> | |
* | |
* @param klazz source class for generating, must not be null | |
* @return generated JBBP DSL script for the class and its fields, it can be empty but can't be null | |
* | |
* @author Igor Maznitsa | |
*/ | |
public static String class2jbbp(final Class<?> klazz) { | |
class Item implements Comparable<Item> { | |
final String fieldName; | |
final Class<?> fieldType; | |
final JBBPBitOrder bitOrder; | |
final JBBPBitNumber bitNumber; | |
final boolean array; | |
final BinType type; | |
final int order; | |
final String extra; | |
Item(final int order, final Bin binAnnotation, final Field fld) { | |
this.array = fld.getType().isArray(); | |
if (this.array) { | |
this.fieldType = fld.getType().getComponentType(); | |
} else { | |
this.fieldType = fld.getType(); | |
} | |
this.fieldName = binAnnotation.name().isEmpty() ? fld.getName() : binAnnotation.name(); | |
this.bitOrder = binAnnotation.bitOrder(); | |
this.bitNumber = binAnnotation.outBitNumber(); | |
this.type = binAnnotation.type(); | |
this.order = binAnnotation.outOrder() < 0 ? order : binAnnotation.outOrder(); | |
String expr = binAnnotation.extra(); | |
expr = expr.startsWith("expr:") ? expr.substring(5) : null; | |
this.extra = expr; | |
} | |
@Override | |
public int compareTo(final Item o) { | |
if (this.order < o.order) { | |
return -1; | |
} | |
if (this.order > o.order) { | |
return 1; | |
} | |
return 0; | |
} | |
@Override | |
public String toString() { | |
final StringBuilder result = new StringBuilder(); | |
switch (this.type) { | |
case UNDEFINED: | |
throw new IllegalArgumentException("Detected undefined field : " + this.fieldName); | |
case STRUCT: | |
case STRUCT_ARRAY: { | |
result.append(this.fieldName); | |
if (this.array) { | |
result.append(" [").append(this.extra == null || this.extra.isEmpty() ? "_" : this.extra).append("] "); | |
} | |
result.append(" {").append(class2jbbp(this.fieldType)).append("}"); | |
} | |
break; | |
default: { | |
final String[] splitted = this.type.name().toLowerCase(Locale.ENGLISH).split("\\_"); | |
result.append(splitted[0]); | |
if (splitted.length > 1) { | |
result.append(" [").append(this.extra == null || this.extra.isEmpty() ? "_" : this.extra).append("]"); | |
} | |
result.append(' ').append(this.fieldName).append("; "); | |
} | |
break; | |
} | |
return result.toString(); | |
} | |
} | |
final List<Item> items = new ArrayList<>(); | |
int index = 0; | |
for (final Field f : klazz.getDeclaredFields()) { | |
final Bin anno = f.getAnnotation(Bin.class); | |
if (anno != null) { | |
items.add(new Item(index++, anno, f)); | |
} | |
} | |
Collections.sort(items); | |
final StringBuilder result = new StringBuilder(); | |
for (final Item i : items) { | |
result.append(i.toString()); | |
} | |
return result.toString(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment