/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.avro.io.parsing; import java.util.HashMap; import java.util.Map; import org.apache.avro.Schema; import org.apache.avro.Schema.Field; /** * The class that generates a grammar suitable to parse Avro data * in JSON format. */ public class JsonGrammarGenerator extends ValidatingGrammarGenerator { /** * Returns the non-terminal that is the start symbol * for the grammar for the grammar for the given schema <tt>sc</tt>. */ public Symbol generate(Schema schema) { return Symbol.root(generate(schema, new HashMap<LitS, Symbol>())); } /** * Returns the non-terminal that is the start symbol * for grammar of the given schema <tt>sc</tt>. If there is already an entry * for the given schema in the given map <tt>seen</tt> then * that entry is returned. Otherwise a new symbol is generated and * an entry is inserted into the map. * @param sc The schema for which the start symbol is required * @param seen A map of schema to symbol mapping done so far. * @return The start symbol for the schema */ public Symbol generate(Schema sc, Map<LitS, Symbol> seen) { switch (sc.getType()) { case NULL: case BOOLEAN: case INT: case LONG: case FLOAT: case DOUBLE: case STRING: case BYTES: case FIXED: case UNION: return super.generate(sc, seen); case ENUM: return Symbol.seq(Symbol.enumLabelsAction(sc.getEnumSymbols()), Symbol.ENUM); case ARRAY: return Symbol.seq(Symbol.repeat(Symbol.ARRAY_END, Symbol.ITEM_END, generate(sc.getElementType(), seen)), Symbol.ARRAY_START); case MAP: return Symbol.seq(Symbol.repeat(Symbol.MAP_END, Symbol.ITEM_END, generate(sc.getValueType(), seen), Symbol.MAP_KEY_MARKER, Symbol.STRING), Symbol.MAP_START); case RECORD: { LitS wsc = new LitS(sc); Symbol rresult = seen.get(wsc); if (rresult == null) { Symbol[] production = new Symbol[sc.getFields().size() * 3 + 2]; rresult = Symbol.seq(production); seen.put(wsc, rresult); int i = production.length; int n = 0; production[--i] = Symbol.RECORD_START; for (Field f : sc.getFields()) { production[--i] = Symbol.fieldAdjustAction(n, f.name()); production[--i] = generate(f.schema(), seen); production[--i] = Symbol.FIELD_END; n++; } production[--i] = Symbol.RECORD_END; } return rresult; } default: throw new RuntimeException("Unexpected schema type"); } } }