package org.odata4j.format.jsonlite; import java.io.Reader; import org.odata4j.core.OCollection; import org.odata4j.core.OCollections; import org.odata4j.core.OComplexObject; import org.odata4j.core.ODataVersion; import org.odata4j.core.OEntity; import org.odata4j.core.OObject; import org.odata4j.core.OSimpleObjects; import org.odata4j.edm.EdmCollectionType; import org.odata4j.edm.EdmDataServices; import org.odata4j.edm.EdmEntitySet; import org.odata4j.edm.EdmEntityType; import org.odata4j.edm.EdmSimpleType; import org.odata4j.edm.EdmType; import org.odata4j.exceptions.NotImplementedException; import org.odata4j.format.Entry; import org.odata4j.format.FormatParser; import org.odata4j.format.FormatParserFactory; import org.odata4j.format.FormatType; import org.odata4j.format.Settings; import org.odata4j.format.json.JsonEntityFormatParser; import org.odata4j.format.json.JsonStreamReaderFactory; import org.odata4j.format.json.JsonStreamReaderFactory.JsonStreamReader; import org.odata4j.format.json.JsonStreamReaderFactory.JsonStreamReader.JsonEvent; import org.odata4j.format.json.JsonStreamReaderFactory.JsonStreamReader.JsonValueEvent; import org.odata4j.format.jsonlite.JsonLiteFeedFormatParser.JsonFeed; /** * Handles the paring of an OCollection in JSON-LITE format. * * @author <a href="mailto:shantanu@synerzip.com">Shantanu Dindokar</a> * */ public class JsonLiteCollectionFormatParser extends JsonLiteFormatParser implements FormatParser<OCollection<? extends OObject>> { private final EdmCollectionType returnType; /** * Instantiates a new json-lite collection format parser. * * @param settings the Settings */ public JsonLiteCollectionFormatParser(Settings settings) { super(settings); returnType = (EdmCollectionType) (settings == null ? null : settings.parseType); } /** * Instantiates a new json-lite collection format parser. * * @param collectionType the EdmCollectionType * @param metadata the EdmDataServices */ public JsonLiteCollectionFormatParser(EdmCollectionType collectionType, EdmDataServices metadata) { super(null); this.metadata = metadata; returnType = collectionType; } /* (non-Javadoc) * @see org.odata4j.format.FormatParser#parse(java.io.Reader) * * */ @Override public OCollection<? extends OObject> parse(Reader reader) { if (this.returnType.getItemType().getClass().isAssignableFrom(EdmEntityType.class)) { return parseFunctionFeed(reader); } JsonStreamReader jsr = JsonStreamReaderFactory.createJsonStreamReader(reader); try { if (isResponse) { ensureNext(jsr); ensureStartObject(jsr.nextEvent()); // the response object // "odata.metadata" property JsonEvent nextEvent = jsr.nextEvent(); if (nextEvent.isStartProperty() && nextEvent.asStartProperty().getName().equalsIgnoreCase(OdataJsonLiteConstant.VALUE_PROPERTY)) { } else { ensureNext(jsr); ensureStartProperty(nextEvent, OdataJsonLiteConstant.METADATA_PROPERTY); ensureEndProperty(jsr.nextEvent()); ensureNext(jsr); ensureStartProperty(jsr.nextEvent(), OdataJsonLiteConstant.VALUE_PROPERTY); } } // parse the entry OCollection<? extends OObject> o = parseCollection(jsr, jsr.nextEvent()); if (isResponse) { ensureEndProperty(jsr.nextEvent()); ensureEndObject(jsr.nextEvent()); } return o; } finally { jsr.close(); } } /** * Function parsing will be handled in separate story. * * @param reader the reader * @return the o collection<? extends o object> */ protected OCollection<? extends OObject> parseFunctionFeed(Reader reader) { EdmEntitySet entitySet = this.metadata.getEdmEntitySet((EdmEntityType) returnType.getItemType()); Settings settings = new Settings( // someone really needs to spend some time on service version negotiation.... ODataVersion.V3, this.metadata, entitySet.getName(), this.entityKey, null, // feed customization mapping this.isResponse, this.returnType.getItemType()); JsonLiteFeedFormatParser parser = new JsonLiteFeedFormatParser(settings); JsonFeed feed = parser.parse(reader); OCollection.Builder<OObject> c = newCollectionBuilder(); for (Entry e : feed.getEntries()) { c.add(e.getEntity()); } return c.build(); //return null; } /** * We make this public so that the JsonLiteParametersFormatParser can use it to read * parameter whose type is collection. * While instantiating JsonLiteCollectionFormatParser from JsonLiteParametersFormatParser * should set odata version, metadata, entitySetName, entityKey in the settings. * * @param jsr the json stream reader * @param event the JsonEvent * @return the collection object */ public OCollection<? extends OObject> parseCollection(JsonStreamReader jsr, JsonEvent event) { ensureStartArray(event); OCollection.Builder<OObject> c = newCollectionBuilder(); if (this.returnType.getItemType().isSimple()) { parseCollectionOfSimpleTypes(c, jsr); } else { FormatParser<? extends OObject> parser = createItemParser(this.returnType.getItemType()); while (jsr.hasNext()) { if (parser instanceof JsonLiteComplexObjectFormatParser) { OComplexObject obj = ((JsonLiteComplexObjectFormatParser) parser).parseSingleObject(jsr, jsr.nextEvent()); // null if not there if (obj != null) { c = c.add(obj); } else { break; } } else if (parser instanceof JsonEntityFormatParser) { OEntity obj = ((JsonEntityFormatParser) parser).parseSingleEntity(jsr); if (obj != null) { c = c.add(obj); } else { break; } } else { throw new NotImplementedException("collections of type: " + this.returnType.getItemType().getFullyQualifiedTypeName() + " not implemented"); } } } // we should see the end of the array ensureEndArray(jsr.previousEvent()); return c.build(); } /** * Parses the collection of simple type. * * @param builder the builder * @param jsr the json stream reader */ protected void parseCollectionOfSimpleTypes(OCollection.Builder<OObject> builder, JsonStreamReader jsr) { while (jsr.hasNext()) { JsonEvent e = jsr.nextEvent(); if (e.isValue()) { JsonValueEvent ve = e.asValue(); builder.add(OSimpleObjects.parse((EdmSimpleType<?>) this.returnType.getItemType(), ve.getValue())); } else if (e.isEndArray()) { break; } else { throw new RuntimeException("invalid JSON content"); } } } protected OCollection.Builder<OObject> newCollectionBuilder() { return OCollections.<OObject> newBuilder(this.returnType.getItemType()); } /** * Provides the appropriate parser depending on the edmtype. * * @param edmType the edm type * @return the format parser<? extends o object> */ protected FormatParser<? extends OObject> createItemParser(EdmType edmType) { // each item is parsed as a standalone item, not a response item Settings s = new Settings( this.version, this.metadata, this.entitySetName, this.entityKey, null, // FeedCustomizationMapping fcMapping, false, // boolean isResponse); edmType); // expected type return FormatParserFactory.getParser(EdmType.getInstanceType(edmType), FormatType.JSON, s); } }