@Override public String readString() throws IOException { advance(Symbol.STRING); if (parser.topSymbol() == Symbol.MAP_KEY_MARKER) { parser.advance(Symbol.MAP_KEY_MARKER); if (in.getCurrentToken() != JsonToken.FIELD_NAME) { throw error("map-key"); } } else { if (in.getCurrentToken() != JsonToken.VALUE_STRING) { throw error("string"); } } String result = in.getText(); in.nextToken(); return result; }
@Override public int readEnum() throws IOException { advance(Symbol.ENUM); Symbol.EnumLabelsAction top = (Symbol.EnumLabelsAction) parser.popSymbol(); if (in.getCurrentToken() == JsonToken.VALUE_STRING) { in.getText(); int n = top.findLabel(in.getText()); if (n >= 0) { in.nextToken(); return n; } throw new AvroTypeException("Unknown symbol in enum " + in.getText()); } else { throw error("fixed"); } }
@Override public int readIndex() throws IOException { advance(Symbol.UNION); Symbol.Alternative a = (Symbol.Alternative) parser.popSymbol(); String label; if (in.getCurrentToken() == JsonToken.VALUE_NULL) { label = "null"; } else if (in.getCurrentToken() == JsonToken.START_OBJECT && in.nextToken() == JsonToken.FIELD_NAME) { label = in.getText(); in.nextToken(); parser.pushSymbol(Symbol.UNION_END); } else { throw error("start-union"); } int n = a.findLabel(label); if (n < 0) throw new AvroTypeException("Unknown union branch " + label); parser.pushSymbol(a.getSymbol(n)); return n; }
@Override public void writeIndex(int unionIndex) throws IOException { parser.advance(Symbol.UNION); Symbol.Alternative top = (Symbol.Alternative) parser.popSymbol(); Symbol symbol = top.getSymbol(unionIndex); if(symbol != Symbol.NULL && isUnionOfNullWithSomething(top)){ // parser.pushSymbol(Symbol.UNION_END); parser.pushSymbol(symbol); return; } if (symbol != Symbol.NULL) { out.writeStartObject(); out.writeFieldName(top.getLabel(unionIndex)); parser.pushSymbol(Symbol.UNION_END); } parser.pushSymbol(symbol); }
@Override public boolean readBoolean() throws IOException { advance(Symbol.BOOLEAN); JsonToken t = in.getCurrentToken(); if (t == JsonToken.VALUE_TRUE || t == JsonToken.VALUE_FALSE) { in.nextToken(); return t == JsonToken.VALUE_TRUE; } else { String s = in.getText(); if(s.equals("false") || s.equals("FALSE") || s.equals("0")) { in.nextToken(); return false; } else if(s.equals("true") || s.equals("TRUE") || s.equals("1")) { in.nextToken(); return true; } throw error("boolean"); } }
@Override public int readInt() throws IOException { advance(Symbol.INT); if (in.getCurrentToken().isNumeric()) { int result = in.getIntValue(); in.nextToken(); return result; } else { try { String s = in.getText(); in.nextToken(); return Integer.parseInt(s); } catch(Exception e) { throw error("int (" + e.getMessage() + ")"); } } }
@Override public long readLong() throws IOException { advance(Symbol.LONG); if (in.getCurrentToken().isNumeric()) { long result = in.getLongValue(); in.nextToken(); return result; } else { try { String s = in.getText(); in.nextToken(); return Long.parseLong(s); } catch(Exception e) { throw error("long (" + e.getMessage() + ")"); } } }
/** * Determine if the symbol tree has an error symbol in it. This would indicate * that the two schemas are not compatible. * * @param rootSymbol * The root symbol to traverse from to look for an error symbol. * @return true if an error symbol exists in the tree. */ private static boolean hasErrorSymbol(Symbol rootSymbol) { if (rootSymbol.production == null) { return false; } for (Symbol s : rootSymbol.production) { if (s == rootSymbol) { continue; } if (s.getClass().equals(Symbol.ErrorAction.class)) { return true; } else { if (s.production != null) { for (Symbol subSymbol : s.production) { if (hasErrorSymbol(subSymbol)) { return true; } } } } } return false; }
/** * Returns true if the Parser contains any Error symbol, indicating that it may fail * for some inputs. */ private static boolean hasErrors(Symbol symbol) { switch(symbol.kind) { case ALTERNATIVE: return hasErrors(((Symbol.Alternative) symbol).symbols); case EXPLICIT_ACTION: return false; case IMPLICIT_ACTION: return symbol instanceof Symbol.ErrorAction; case REPEATER: Symbol.Repeater r = (Symbol.Repeater) symbol; return hasErrors(r.end) || hasErrors(r.production); case ROOT: return hasErrors(Arrays.copyOfRange(symbol.production, 1, symbol.production.length)); case SEQUENCE: return hasErrors(symbol.production); case TERMINAL: return false; default: throw new RuntimeException("unknown symbol kind: " + symbol.kind); } }
@Override public void readNull() throws IOException { advance(Symbol.NULL); if (in.getCurrentToken() == JsonToken.VALUE_NULL) { in.nextToken(); } else { throw error("null"); } }
@Override public boolean readBoolean() throws IOException { advance(Symbol.BOOLEAN); JsonToken t = in.getCurrentToken(); if (t == JsonToken.VALUE_TRUE || t == JsonToken.VALUE_FALSE) { in.nextToken(); return t == JsonToken.VALUE_TRUE; } else { throw error("boolean"); } }
@Override public int readInt() throws IOException { advance(Symbol.INT); if (in.getCurrentToken().isNumeric()) { int result = in.getIntValue(); in.nextToken(); return result; } else { throw error("int"); } }
@Override public long readLong() throws IOException { advance(Symbol.LONG); if (in.getCurrentToken().isNumeric()) { long result = in.getLongValue(); in.nextToken(); return result; } else { throw error("long"); } }
@Override public float readFloat() throws IOException { advance(Symbol.FLOAT); if (in.getCurrentToken().isNumeric()) { float result = in.getFloatValue(); in.nextToken(); return result; } else { throw error("float"); } }
@Override public double readDouble() throws IOException { advance(Symbol.DOUBLE); if (in.getCurrentToken().isNumeric()) { double result = in.getDoubleValue(); in.nextToken(); return result; } else { throw error("double"); } }
@Override public void skipString() throws IOException { advance(Symbol.STRING); if (parser.topSymbol() == Symbol.MAP_KEY_MARKER) { parser.advance(Symbol.MAP_KEY_MARKER); if (in.getCurrentToken() != JsonToken.FIELD_NAME) { throw error("map-key"); } } else { if (in.getCurrentToken() != JsonToken.VALUE_STRING) { throw error("string"); } } in.nextToken(); }
@Override public ByteBuffer readBytes(ByteBuffer old) throws IOException { advance(Symbol.BYTES); if (in.getCurrentToken() == JsonToken.VALUE_STRING) { byte[] result = readByteArray(); in.nextToken(); return ByteBuffer.wrap(result); } else { throw error("bytes"); } }
@Override public void skipBytes() throws IOException { advance(Symbol.BYTES); if (in.getCurrentToken() == JsonToken.VALUE_STRING) { in.nextToken(); } else { throw error("bytes"); } }
private void checkFixed(int size) throws IOException { advance(Symbol.FIXED); Symbol.IntCheckAction top = (Symbol.IntCheckAction) parser.popSymbol(); if (size != top.size) { throw new AvroTypeException( "Incorrect length for fixed binary: expected " + top.size + " but received " + size + " bytes."); } }
@Override public long readArrayStart() throws IOException { advance(Symbol.ARRAY_START); if (in.getCurrentToken() == JsonToken.START_ARRAY) { in.nextToken(); return doArrayNext(); } else { throw error("array-start"); } }
private long doArrayNext() throws IOException { if (in.getCurrentToken() == JsonToken.END_ARRAY) { parser.advance(Symbol.ARRAY_END); in.nextToken(); return 0; } else { return 1; } }
@Override public long skipArray() throws IOException { advance(Symbol.ARRAY_START); if (in.getCurrentToken() == JsonToken.START_ARRAY) { in.skipChildren(); in.nextToken(); advance(Symbol.ARRAY_END); } else { throw error("array-start"); } return 0; }
@Override public long readMapStart() throws IOException { advance(Symbol.MAP_START); if (in.getCurrentToken() == JsonToken.START_OBJECT) { in.nextToken(); return doMapNext(); } else { throw error("map-start"); } }
private long doMapNext() throws IOException { if (in.getCurrentToken() == JsonToken.END_OBJECT) { in.nextToken(); advance(Symbol.MAP_END); return 0; } else { return 1; } }
@Override public long skipMap() throws IOException { advance(Symbol.MAP_START); if (in.getCurrentToken() == JsonToken.START_OBJECT) { in.skipChildren(); in.nextToken(); advance(Symbol.MAP_END); } else { throw error("map-start"); } return 0; }
@Override public void writeString(String str) throws IOException { parser.advance(Symbol.STRING); if (parser.topSymbol() == Symbol.MAP_KEY_MARKER) { parser.advance(Symbol.MAP_KEY_MARKER); out.writeFieldName(str); } else { out.writeString(str); } }
@Override public void writeFixed(byte[] bytes, int start, int len) throws IOException { parser.advance(Symbol.FIXED); Symbol.IntCheckAction top = (Symbol.IntCheckAction) parser.popSymbol(); if (len != top.size) { throw new AvroTypeException( "Incorrect length for fixed binary: expected " + top.size + " but received " + len + " bytes."); } writeByteArray(bytes, start, len); }
@Override public void writeEnum(int e) throws IOException { parser.advance(Symbol.ENUM); Symbol.EnumLabelsAction top = (Symbol.EnumLabelsAction) parser.popSymbol(); if (e < 0 || e >= top.size) { throw new AvroTypeException("Enumeration out of range: max is " + top.size + " but received " + e); } out.writeString(top.getLabel(e)); }
@Override public void writeArrayStart() throws IOException { parser.advance(Symbol.ARRAY_START); out.writeStartArray(); push(); isEmpty.set(depth()); }
@Override public void writeArrayEnd() throws IOException { if (!isEmpty.get(pos)) { parser.advance(Symbol.ITEM_END); } pop(); parser.advance(Symbol.ARRAY_END); out.writeEndArray(); }
@Override public void writeMapStart() throws IOException { push(); isEmpty.set(depth()); parser.advance(Symbol.MAP_START); out.writeStartObject(); }
@Override public void writeMapEnd() throws IOException { if (!isEmpty.get(pos)) { parser.advance(Symbol.ITEM_END); } pop(); parser.advance(Symbol.MAP_END); out.writeEndObject(); }
@Override public void startItem() throws IOException { if (!isEmpty.get(pos)) { parser.advance(Symbol.ITEM_END); } super.startItem(); isEmpty.clear(depth()); }
@Override public void writeIndex(int unionIndex) throws IOException { parser.advance(Symbol.UNION); Symbol.Alternative top = (Symbol.Alternative) parser.popSymbol(); Symbol symbol = top.getSymbol(unionIndex); // Removed non-null handling here parser.pushSymbol(symbol); }
@Override public Symbol doAction(Symbol input, Symbol top) throws IOException { if (top instanceof Symbol.FieldAdjustAction) { Symbol.FieldAdjustAction fa = (Symbol.FieldAdjustAction) top; out.writeFieldName(fa.fname); } else if (top == Symbol.RECORD_START) { out.writeStartObject(); } else if (top == Symbol.RECORD_END || top == Symbol.UNION_END) { out.writeEndObject(); } else if (top != Symbol.FIELD_END) { throw new AvroTypeException("Unknown action symbol " + top); } return null; }