You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by il...@apache.org on 2014/03/24 10:42:24 UTC
[35/50] [abbrv] [OLINGO-200] Moving Atom and JSON (de)serializer to
commons
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata4/blob/fac84b3e/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomPropertyDeserializer.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomPropertyDeserializer.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomPropertyDeserializer.java
new file mode 100644
index 0000000..99231b4
--- /dev/null
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomPropertyDeserializer.java
@@ -0,0 +1,214 @@
+/*
+ * 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.olingo.commons.core.data;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.Attribute;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.olingo.commons.api.Constants;
+import org.apache.olingo.commons.api.data.CollectionValue;
+import org.apache.olingo.commons.api.data.ComplexValue;
+import org.apache.olingo.commons.api.data.Value;
+import org.apache.olingo.commons.api.domain.ODataPropertyType;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
+import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
+import org.apache.olingo.commons.core.edm.EdmTypeInfo;
+
+class AtomPropertyDeserializer extends AbstractAtomDealer {
+
+ private final AtomGeoValueDeserializer geoDeserializer;
+
+ public AtomPropertyDeserializer(final ODataServiceVersion version) {
+ super(version);
+ this.geoDeserializer = new AtomGeoValueDeserializer();
+ }
+
+ private Value fromPrimitive(final XMLEventReader reader, final StartElement start,
+ final EdmTypeInfo typeInfo) throws XMLStreamException {
+
+ Value value = null;
+
+ boolean foundEndProperty = false;
+ while (reader.hasNext() && !foundEndProperty) {
+ final XMLEvent event = reader.nextEvent();
+
+ if (event.isStartElement() && typeInfo != null && typeInfo.getPrimitiveTypeKind().isGeospatial()) {
+ final EdmPrimitiveTypeKind geoType = EdmPrimitiveTypeKind.valueOfFQN(
+ version, typeInfo.getFullQualifiedName().toString());
+ value = new GeospatialValueImpl(this.geoDeserializer.deserialize(reader, event.asStartElement(), geoType));
+ }
+
+ if (event.isCharacters() && !event.asCharacters().isWhiteSpace()
+ && (typeInfo == null || !typeInfo.getPrimitiveTypeKind().isGeospatial())) {
+
+ value = new PrimitiveValueImpl(event.asCharacters().getData());
+ }
+
+ if (event.isEndElement() && start.getName().equals(event.asEndElement().getName())) {
+ foundEndProperty = true;
+ }
+ }
+
+ return value;
+ }
+
+ private ComplexValue fromComplex(final XMLEventReader reader, final StartElement start)
+ throws XMLStreamException {
+
+ final ComplexValue value = new ComplexValueImpl();
+
+ boolean foundEndProperty = false;
+ while (reader.hasNext() && !foundEndProperty) {
+ final XMLEvent event = reader.nextEvent();
+
+ if (event.isStartElement()) {
+ value.get().add(deserialize(reader, event.asStartElement()));
+ }
+
+ if (event.isEndElement() && start.getName().equals(event.asEndElement().getName())) {
+ foundEndProperty = true;
+ }
+ }
+
+ return value;
+ }
+
+ private CollectionValue fromCollection(final XMLEventReader reader, final StartElement start,
+ final EdmTypeInfo typeInfo) throws XMLStreamException {
+
+ final CollectionValueImpl value = new CollectionValueImpl();
+
+ final EdmTypeInfo type = typeInfo == null
+ ? null
+ : new EdmTypeInfo.Builder().setTypeExpression(typeInfo.getFullQualifiedName().toString()).build();
+
+ boolean foundEndProperty = false;
+ while (reader.hasNext() && !foundEndProperty) {
+ final XMLEvent event = reader.nextEvent();
+
+ if (event.isStartElement()) {
+ switch (guessPropertyType(reader)) {
+ case COMPLEX:
+ value.get().add(fromComplex(reader, event.asStartElement()));
+ break;
+
+ case PRIMITIVE:
+ value.get().add(fromPrimitive(reader, event.asStartElement(), type));
+ break;
+
+ default:
+ // do not add null or empty values
+ }
+ }
+
+ if (event.isEndElement() && start.getName().equals(event.asEndElement().getName())) {
+ foundEndProperty = true;
+ }
+ }
+
+ return value;
+ }
+
+ private ODataPropertyType guessPropertyType(final XMLEventReader reader) throws XMLStreamException {
+ XMLEvent child = null;
+ while (reader.hasNext() && child == null) {
+ final XMLEvent event = reader.peek();
+ if (event.isCharacters() && event.asCharacters().isWhiteSpace()) {
+ reader.nextEvent();
+ } else {
+ child = event;
+ }
+ }
+
+ ODataPropertyType type = null;
+ if (child == null) {
+ type = ODataPropertyType.PRIMITIVE;
+ } else {
+ if (child.isStartElement()) {
+ if (Constants.NS_GML.equals(child.asStartElement().getName().getNamespaceURI())) {
+ type = ODataPropertyType.PRIMITIVE;
+ } else if (elementQName.equals(child.asStartElement().getName())) {
+ type = ODataPropertyType.COLLECTION;
+ } else {
+ type = ODataPropertyType.COMPLEX;
+ }
+ } else if (child.isCharacters()) {
+ type = ODataPropertyType.PRIMITIVE;
+ } else {
+ type = ODataPropertyType.EMPTY;
+ }
+ }
+
+ return type;
+ }
+
+ public AtomPropertyImpl deserialize(final XMLEventReader reader, final StartElement start)
+ throws XMLStreamException {
+
+ final AtomPropertyImpl property = new AtomPropertyImpl();
+ property.setName(start.getName().getLocalPart());
+
+ final Attribute typeAttr = start.getAttributeByName(this.typeQName);
+ if (typeAttr != null) {
+ property.setType(typeAttr.getValue());
+ }
+
+ Value value;
+ final Attribute nullAttr = start.getAttributeByName(this.nullQName);
+ if (nullAttr == null) {
+ final EdmTypeInfo typeInfo = StringUtils.isBlank(property.getType())
+ ? null
+ : new EdmTypeInfo.Builder().setTypeExpression(property.getType()).build();
+
+ final ODataPropertyType propType = typeInfo == null
+ ? guessPropertyType(reader)
+ : typeInfo.isCollection()
+ ? ODataPropertyType.COLLECTION
+ : typeInfo.isPrimitiveType()
+ ? ODataPropertyType.PRIMITIVE
+ : ODataPropertyType.COMPLEX;
+
+ switch (propType) {
+ case COLLECTION:
+ value = fromCollection(reader, start, typeInfo);
+ break;
+
+ case COMPLEX:
+ value = fromComplex(reader, start);
+ break;
+
+ case PRIMITIVE:
+ value = fromPrimitive(reader, start, typeInfo);
+ break;
+
+ case EMPTY:
+ default:
+ value = new PrimitiveValueImpl(StringUtils.EMPTY);
+ }
+ } else {
+ value = new NullValueImpl();
+ }
+ property.setValue(value);
+
+ return property;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata4/blob/fac84b3e/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomPropertyImpl.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomPropertyImpl.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomPropertyImpl.java
new file mode 100644
index 0000000..9688db2
--- /dev/null
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomPropertyImpl.java
@@ -0,0 +1,25 @@
+/*
+ * 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.olingo.commons.core.data;
+
+public class AtomPropertyImpl extends AbstractPropertyImpl {
+
+ private static final long serialVersionUID = 48748492242474814L;
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata4/blob/fac84b3e/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomPropertySerializer.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomPropertySerializer.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomPropertySerializer.java
new file mode 100644
index 0000000..8d2a8e1
--- /dev/null
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomPropertySerializer.java
@@ -0,0 +1,88 @@
+/*
+ * 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.olingo.commons.core.data;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.olingo.commons.api.Constants;
+import org.apache.olingo.commons.api.data.CollectionValue;
+import org.apache.olingo.commons.api.data.Property;
+import org.apache.olingo.commons.api.data.Value;
+import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
+
+class AtomPropertySerializer extends AbstractAtomDealer {
+
+ private final AtomGeoValueSerializer geoSerializer;
+
+ public AtomPropertySerializer(final ODataServiceVersion version) {
+ super(version);
+ this.geoSerializer = new AtomGeoValueSerializer();
+ }
+
+ private void collection(final XMLStreamWriter writer, final CollectionValue value) throws XMLStreamException {
+ for (Value item : value.get()) {
+ writer.writeStartElement(Constants.PREFIX_DATASERVICES, Constants.ELEM_ELEMENT,
+ version.getNamespaceMap().get(ODataServiceVersion.NS_DATASERVICES));
+ value(writer, item);
+ writer.writeEndElement();
+ }
+ }
+
+ private void value(final XMLStreamWriter writer, final Value value) throws XMLStreamException {
+ if (value.isSimple()) {
+ writer.writeCharacters(value.asSimple().get());
+ } else if (value.isGeospatial()) {
+ this.geoSerializer.serialize(writer, value.asGeospatial().get());
+ } else if (value.isCollection()) {
+ collection(writer, value.asCollection());
+ } else if (value.isComplex()) {
+ for (Property property : value.asComplex().get()) {
+ property(writer, property, false);
+ }
+ }
+ }
+
+ public void property(final XMLStreamWriter writer, final Property property, final boolean standalone)
+ throws XMLStreamException {
+
+ writer.writeStartElement(Constants.PREFIX_DATASERVICES, property.getName(),
+ version.getNamespaceMap().get(ODataServiceVersion.NS_DATASERVICES));
+ if (standalone) {
+ namespaces(writer);
+ }
+ if (StringUtils.isNotBlank(property.getType())) {
+ writer.writeAttribute(Constants.PREFIX_METADATA, version.getNamespaceMap().get(ODataServiceVersion.NS_METADATA),
+ Constants.ATTR_TYPE, property.getType());
+ }
+
+ if (property.getValue().isNull()) {
+ writer.writeAttribute(Constants.PREFIX_METADATA, version.getNamespaceMap().get(ODataServiceVersion.NS_METADATA),
+ Constants.ATTR_NULL, Boolean.TRUE.toString());
+ } else {
+ value(writer, property.getValue());
+ }
+
+ writer.writeEndElement();
+ }
+
+ public void property(final XMLStreamWriter writer, final Property property) throws XMLStreamException {
+ property(writer, property, true);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata4/blob/fac84b3e/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomSerializer.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomSerializer.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomSerializer.java
new file mode 100644
index 0000000..4c6fb3a
--- /dev/null
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomSerializer.java
@@ -0,0 +1,264 @@
+/*
+ * 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.olingo.commons.core.data;
+
+import java.io.Writer;
+import java.util.Collections;
+import java.util.List;
+import javax.xml.XMLConstants;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.olingo.commons.api.Constants;
+import org.apache.olingo.commons.api.data.Entry;
+import org.apache.olingo.commons.api.data.Feed;
+import org.apache.olingo.commons.api.data.Link;
+import org.apache.olingo.commons.api.data.Property;
+import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
+import org.apache.olingo.commons.api.format.ContentType;
+
+public class AtomSerializer extends AbstractAtomDealer {
+
+ private static final XMLOutputFactory FACTORY = XMLOutputFactory.newInstance();
+
+ private final AtomPropertySerializer propSerializer;
+
+ public AtomSerializer(final ODataServiceVersion version) {
+ super(version);
+ this.propSerializer = new AtomPropertySerializer(version);
+ }
+
+ private void startDocument(final XMLStreamWriter writer, final String rootElement) throws XMLStreamException {
+ writer.writeStartDocument();
+ writer.setDefaultNamespace(Constants.NS_ATOM);
+
+ writer.writeStartElement(rootElement);
+
+ namespaces(writer);
+ }
+
+ private void property(final Writer outWriter, final Property property) throws XMLStreamException {
+ final XMLStreamWriter writer = FACTORY.createXMLStreamWriter(outWriter);
+
+ writer.writeStartDocument();
+
+ propSerializer.property(writer, property);
+
+ writer.writeEndDocument();
+ writer.flush();
+ }
+
+ private void links(final XMLStreamWriter writer, final List<Link> links) throws XMLStreamException {
+ for (Link link : links) {
+ writer.writeStartElement(Constants.ATOM_ELEM_LINK);
+
+ if (StringUtils.isNotBlank(link.getRel())) {
+ writer.writeAttribute(Constants.ATTR_REL, link.getRel());
+ }
+ if (StringUtils.isNotBlank(link.getTitle())) {
+ writer.writeAttribute(Constants.ATTR_TITLE, link.getTitle());
+ }
+ if (StringUtils.isNotBlank(link.getHref())) {
+ writer.writeAttribute(Constants.ATTR_HREF, link.getHref());
+ }
+ if (StringUtils.isNotBlank(link.getType())) {
+ writer.writeAttribute(Constants.ATTR_TYPE, link.getType());
+ }
+
+ if (link.getInlineEntry() != null || link.getInlineFeed() != null) {
+ writer.writeStartElement(Constants.PREFIX_METADATA, Constants.ATOM_ELEM_INLINE,
+ version.getNamespaceMap().get(ODataServiceVersion.NS_METADATA));
+
+ if (link.getInlineEntry() != null) {
+ writer.writeStartElement(Constants.ATOM_ELEM_ENTRY);
+ entry(writer, link.getInlineEntry());
+ writer.writeEndElement();
+ }
+ if (link.getInlineFeed() != null) {
+ writer.writeStartElement(Constants.ATOM_ELEM_FEED);
+ feed(writer, link.getInlineFeed());
+ writer.writeEndElement();
+ }
+
+ writer.writeEndElement();
+ }
+
+ writer.writeEndElement();
+ }
+ }
+
+ private void common(final XMLStreamWriter writer, final AbstractAtomObject object) throws XMLStreamException {
+ if (StringUtils.isNotBlank(object.getTitle())) {
+ writer.writeStartElement(Constants.ATOM_ELEM_TITLE);
+ writer.writeAttribute(Constants.ATTR_TYPE, TYPE_TEXT);
+ writer.writeCharacters(object.getTitle());
+ writer.writeEndElement();
+ }
+
+ if (StringUtils.isNotBlank(object.getSummary())) {
+ writer.writeStartElement(Constants.ATOM_ELEM_SUMMARY);
+ writer.writeAttribute(Constants.ATTR_TYPE, "text");
+ writer.writeCharacters(object.getSummary());
+ writer.writeEndElement();
+ }
+ }
+
+ private void properties(final XMLStreamWriter writer, final List<Property> properties) throws XMLStreamException {
+ for (Property property : properties) {
+ propSerializer.property(writer, property, false);
+ }
+ }
+
+ private void entry(final XMLStreamWriter writer, final Entry entry) throws XMLStreamException {
+ if (entry.getBaseURI() != null) {
+ writer.writeAttribute(XMLConstants.XML_NS_URI, Constants.ATTR_XML_BASE, entry.getBaseURI().toASCIIString());
+ }
+
+ if (StringUtils.isNotBlank(entry.getId())) {
+ writer.writeStartElement(Constants.ATOM_ELEM_ID);
+ writer.writeCharacters(entry.getId());
+ writer.writeEndElement();
+ }
+
+ writer.writeStartElement(Constants.ATOM_ELEM_CATEGORY);
+ writer.writeAttribute(Constants.ATOM_ATTR_SCHEME, version.getNamespaceMap().get(ODataServiceVersion.NS_SCHEME));
+ writer.writeAttribute(Constants.ATOM_ATTR_TERM, entry.getType());
+ writer.writeEndElement();
+
+ if (entry instanceof AbstractAtomObject) {
+ common(writer, (AbstractAtomObject) entry);
+ }
+
+ links(writer, entry.getAssociationLinks());
+ links(writer, entry.getNavigationLinks());
+ links(writer, entry.getMediaEditLinks());
+
+ writer.writeStartElement(Constants.ATOM_ELEM_CONTENT);
+ if (entry.isMediaEntry()) {
+ if (StringUtils.isNotBlank(entry.getMediaContentType())) {
+ writer.writeAttribute(Constants.ATTR_TYPE, entry.getMediaContentType());
+ }
+ if (StringUtils.isNotBlank(entry.getMediaContentSource())) {
+ writer.writeAttribute(Constants.ATOM_ATTR_SRC, entry.getMediaContentSource());
+ }
+ writer.writeEndElement();
+
+ writer.writeStartElement(version.getNamespaceMap().get(ODataServiceVersion.NS_METADATA), Constants.PROPERTIES);
+ properties(writer, entry.getProperties());
+ } else {
+ writer.writeAttribute(Constants.ATTR_TYPE, ContentType.APPLICATION_XML);
+ writer.writeStartElement(version.getNamespaceMap().get(ODataServiceVersion.NS_METADATA), Constants.PROPERTIES);
+ properties(writer, entry.getProperties());
+ writer.writeEndElement();
+ }
+ writer.writeEndElement();
+ }
+
+ private void entry(final Writer outWriter, final Entry entry) throws XMLStreamException {
+ final XMLStreamWriter writer = FACTORY.createXMLStreamWriter(outWriter);
+
+ startDocument(writer, Constants.ATOM_ELEM_ENTRY);
+
+ entry(writer, entry);
+
+ writer.writeEndElement();
+ writer.writeEndDocument();
+ writer.flush();
+ }
+
+ private void feed(final XMLStreamWriter writer, final Feed feed) throws XMLStreamException {
+ if (feed.getBaseURI() != null) {
+ writer.writeAttribute(XMLConstants.XML_NS_URI, Constants.ATTR_XML_BASE, feed.getBaseURI().toASCIIString());
+ }
+
+ if (feed.getCount() != null) {
+ writer.writeStartElement(
+ version.getNamespaceMap().get(ODataServiceVersion.NS_METADATA), Constants.ATOM_ELEM_COUNT);
+ writer.writeCharacters(Integer.toString(feed.getCount()));
+ writer.writeEndElement();
+ }
+
+ if (StringUtils.isNotBlank(feed.getId())) {
+ writer.writeStartElement(Constants.ATOM_ELEM_ID);
+ writer.writeCharacters(feed.getId());
+ writer.writeEndElement();
+ }
+
+ if (feed instanceof AbstractAtomObject) {
+ common(writer, (AbstractAtomObject) feed);
+ }
+
+ for (Entry entry : feed.getEntries()) {
+ writer.writeStartElement(Constants.ATOM_ELEM_ENTRY);
+ entry(writer, entry);
+ writer.writeEndElement();
+ }
+
+ if (feed.getNext() != null) {
+ final LinkImpl next = new LinkImpl();
+ next.setRel(Constants.NEXT_LINK_REL);
+ next.setHref(feed.getNext().toASCIIString());
+
+ links(writer, Collections.<Link>singletonList(next));
+ }
+ }
+
+ private void feed(final Writer outWriter, final Feed feed) throws XMLStreamException {
+ final XMLStreamWriter writer = FACTORY.createXMLStreamWriter(outWriter);
+
+ startDocument(writer, Constants.ATOM_ELEM_FEED);
+
+ feed(writer, feed);
+
+ writer.writeEndElement();
+ writer.writeEndDocument();
+ writer.flush();
+ }
+
+ private void link(final Writer outWriter, final Link link) throws XMLStreamException {
+ final XMLStreamWriter writer = FACTORY.createXMLStreamWriter(outWriter);
+
+ writer.writeStartDocument();
+
+ writer.writeStartElement(Constants.ELEM_LINKS);
+ writer.writeDefaultNamespace(version.getNamespaceMap().get(ODataServiceVersion.NS_DATASERVICES));
+
+ writer.writeStartElement(Constants.ELEM_URI);
+ writer.writeCharacters(link.getHref());
+ writer.writeEndElement();
+
+ writer.writeEndElement();
+
+ writer.writeEndDocument();
+ writer.flush();
+ }
+
+ public <T> void write(final Writer writer, final T obj) throws XMLStreamException {
+ if (obj instanceof Feed) {
+ feed(writer, (Feed) obj);
+ } else if (obj instanceof Entry) {
+ entry(writer, (Entry) obj);
+ } else if (obj instanceof Property) {
+ property(writer, (Property) obj);
+ } else if (obj instanceof Link) {
+ link(writer, (Link) obj);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata4/blob/fac84b3e/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/CollectionValueImpl.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/CollectionValueImpl.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/CollectionValueImpl.java
new file mode 100644
index 0000000..02c6d43
--- /dev/null
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/CollectionValueImpl.java
@@ -0,0 +1,40 @@
+/*
+ * 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.olingo.commons.core.data;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.olingo.commons.api.data.CollectionValue;
+import org.apache.olingo.commons.api.data.Value;
+
+public class CollectionValueImpl extends AbstractValue implements CollectionValue {
+
+ private final List<Value> value = new ArrayList<Value>();
+
+ @Override
+ public boolean isCollection() {
+ return true;
+ }
+
+ @Override
+ public List<Value> get() {
+ return value;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata4/blob/fac84b3e/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/ComplexValueImpl.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/ComplexValueImpl.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/ComplexValueImpl.java
new file mode 100644
index 0000000..0144f83
--- /dev/null
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/ComplexValueImpl.java
@@ -0,0 +1,40 @@
+/*
+ * 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.olingo.commons.core.data;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.olingo.commons.api.data.ComplexValue;
+import org.apache.olingo.commons.api.data.Property;
+
+public class ComplexValueImpl extends AbstractValue implements ComplexValue {
+
+ private final List<Property> value = new ArrayList<Property>();
+
+ @Override
+ public boolean isComplex() {
+ return true;
+ }
+
+ @Override
+ public List<Property> get() {
+ return value;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata4/blob/fac84b3e/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/GeospatialValueImpl.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/GeospatialValueImpl.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/GeospatialValueImpl.java
new file mode 100644
index 0000000..e278334
--- /dev/null
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/GeospatialValueImpl.java
@@ -0,0 +1,42 @@
+/*
+ * 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.olingo.commons.core.data;
+
+import org.apache.olingo.commons.api.data.GeospatialValue;
+import org.apache.olingo.commons.api.edm.geo.Geospatial;
+
+public class GeospatialValueImpl extends AbstractValue implements GeospatialValue {
+
+ private final Geospatial value;
+
+ public GeospatialValueImpl(final Geospatial value) {
+ this.value = value;
+ }
+
+ @Override
+ public boolean isGeospatial() {
+ return true;
+ }
+
+ @Override
+ public Geospatial get() {
+ return value;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata4/blob/fac84b3e/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONEntryDeserializer.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONEntryDeserializer.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONEntryDeserializer.java
new file mode 100644
index 0000000..3647fac
--- /dev/null
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONEntryDeserializer.java
@@ -0,0 +1,241 @@
+/*
+ * 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.olingo.commons.core.data;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.ObjectCodec;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import java.io.IOException;
+import java.net.URI;
+import java.text.ParseException;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import org.apache.olingo.commons.api.Constants;
+import org.apache.olingo.commons.api.data.Link;
+import org.apache.olingo.commons.api.domain.ODataLinkType;
+import org.apache.olingo.commons.api.domain.ODataOperation;
+import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
+
+/**
+ * Reads JSON string into an entry.
+ * <br/>
+ * If metadata information is available, the corresponding entry fields and content will be populated.
+ */
+public class JSONEntryDeserializer extends AbstractJsonDeserializer<JSONEntryImpl> {
+
+ private String getTitle(final Map.Entry<String, JsonNode> entry) {
+ return entry.getKey().substring(0, entry.getKey().indexOf('@'));
+ }
+
+ private String setInline(final String name, final String suffix, final ObjectNode tree,
+ final ObjectCodec codec, final LinkImpl link) throws IOException {
+
+ final String entryNamePrefix = name.substring(0, name.indexOf(suffix));
+ if (tree.has(entryNamePrefix)) {
+ final JsonNode inline = tree.path(entryNamePrefix);
+
+ if (inline instanceof ObjectNode) {
+ link.setType(ODataLinkType.ENTITY_NAVIGATION.toString());
+ link.setInlineEntry(inline.traverse(codec).readValuesAs(JSONEntryImpl.class).next());
+ }
+
+ if (inline instanceof ArrayNode) {
+ link.setType(ODataLinkType.ENTITY_SET_NAVIGATION.toString());
+
+ final JSONFeedImpl feed = new JSONFeedImpl();
+ final Iterator<JsonNode> entries = ((ArrayNode) inline).elements();
+ while (entries.hasNext()) {
+ feed.getEntries().add(entries.next().traverse(codec).readValuesAs(JSONEntryImpl.class).next());
+ }
+
+ link.setInlineFeed(feed);
+ }
+ }
+ return entryNamePrefix;
+ }
+
+ @Override
+ protected JSONEntryImpl doDeserialize(final JsonParser parser, final DeserializationContext ctxt)
+ throws IOException, JsonProcessingException {
+
+ final ObjectNode tree = (ObjectNode) parser.getCodec().readTree(parser);
+
+ if (tree.has(Constants.JSON_VALUE) && tree.get(Constants.JSON_VALUE).isArray()) {
+ throw new JsonParseException("Expected OData Entity, found EntitySet", parser.getCurrentLocation());
+ }
+
+ final JSONEntryImpl entry = new JSONEntryImpl();
+
+ if (tree.hasNonNull(Constants.JSON_METADATA)) {
+ entry.setMetadata(URI.create(tree.get(Constants.JSON_METADATA).textValue()));
+ tree.remove(Constants.JSON_METADATA);
+ }
+
+ if (tree.hasNonNull(Constants.JSON_MEDIA_ETAG)) {
+ entry.setMediaETag(tree.get(Constants.JSON_MEDIA_ETAG).textValue());
+ tree.remove(Constants.JSON_MEDIA_ETAG);
+ }
+
+ if (tree.hasNonNull(Constants.JSON_ETAG)) {
+ entry.setETag(tree.get(Constants.JSON_ETAG).textValue());
+ tree.remove(Constants.JSON_ETAG);
+ }
+
+ if (tree.hasNonNull(Constants.JSON_TYPE)) {
+ entry.setType(tree.get(Constants.JSON_TYPE).textValue());
+ tree.remove(Constants.JSON_TYPE);
+ }
+
+ if (tree.hasNonNull(Constants.JSON_ID)) {
+ try {
+ entry.setId(tree.get(Constants.JSON_ID).textValue());
+ } catch (ParseException e) {
+ throw new JsonMappingException("While parsing Atom entry or feed common elements", e);
+ }
+ tree.remove(Constants.JSON_ID);
+ }
+
+ if (tree.hasNonNull(Constants.JSON_READ_LINK)) {
+ final LinkImpl link = new LinkImpl();
+ link.setRel(Constants.SELF_LINK_REL);
+ link.setHref(tree.get(Constants.JSON_READ_LINK).textValue());
+ entry.setSelfLink(link);
+
+ tree.remove(Constants.JSON_READ_LINK);
+ }
+
+ if (tree.hasNonNull(Constants.JSON_EDIT_LINK)) {
+ final LinkImpl link = new LinkImpl();
+ link.setRel(Constants.EDIT_LINK_REL);
+ link.setHref(tree.get(Constants.JSON_EDIT_LINK).textValue());
+ entry.setEditLink(link);
+
+ tree.remove(Constants.JSON_EDIT_LINK);
+ }
+
+ if (tree.hasNonNull(Constants.JSON_MEDIAREAD_LINK)) {
+ entry.setMediaContentSource(tree.get(Constants.JSON_MEDIAREAD_LINK).textValue());
+ tree.remove(Constants.JSON_MEDIAREAD_LINK);
+ }
+ if (tree.hasNonNull(Constants.JSON_MEDIAEDIT_LINK)) {
+ tree.remove(Constants.JSON_MEDIAEDIT_LINK);
+ }
+ if (tree.hasNonNull(Constants.JSON_MEDIA_CONTENT_TYPE)) {
+ entry.setMediaContentType(tree.get(Constants.JSON_MEDIA_CONTENT_TYPE).textValue());
+ tree.remove(Constants.JSON_MEDIA_CONTENT_TYPE);
+ }
+
+ final Set<String> toRemove = new HashSet<String>();
+ for (final Iterator<Map.Entry<String, JsonNode>> itor = tree.fields(); itor.hasNext();) {
+ final Map.Entry<String, JsonNode> field = itor.next();
+
+ if (field.getKey().endsWith(Constants.JSON_NAVIGATION_LINK_SUFFIX)) {
+ final LinkImpl link = new LinkImpl();
+ link.setTitle(getTitle(field));
+ link.setRel(version.getNamespaceMap().get(ODataServiceVersion.NAVIGATION_LINK_REL) + getTitle(field));
+
+ if (field.getValue().isValueNode()) {
+ link.setHref(field.getValue().textValue());
+ link.setType(ODataLinkType.ENTITY_NAVIGATION.toString());
+ }
+ // NOTE: this should be expected to happen, but it isn't - at least up to OData 4.0
+ /* if (field.getValue().isArray()) {
+ * link.setHref(field.getValue().asText());
+ * link.setType(ODataLinkType.ENTITY_SET_NAVIGATION.toString());
+ * } */
+
+ entry.getNavigationLinks().add(link);
+
+ toRemove.add(field.getKey());
+ toRemove.add(setInline(field.getKey(), Constants.JSON_NAVIGATION_LINK_SUFFIX, tree, parser.getCodec(), link));
+ } else if (field.getKey().endsWith(Constants.JSON_ASSOCIATION_LINK_SUFFIX)) {
+ final LinkImpl link = new LinkImpl();
+ link.setTitle(getTitle(field));
+ link.setRel(version.getNamespaceMap().get(ODataServiceVersion.ASSOCIATION_LINK_REL) + getTitle(field));
+ link.setHref(field.getValue().textValue());
+ link.setType(ODataLinkType.ASSOCIATION.toString());
+ entry.getAssociationLinks().add(link);
+
+ toRemove.add(field.getKey());
+ } else if (field.getKey().endsWith(Constants.JSON_MEDIAEDIT_LINK_SUFFIX)) {
+ final LinkImpl link = new LinkImpl();
+ link.setTitle(getTitle(field));
+ link.setRel(version.getNamespaceMap().get(ODataServiceVersion.MEDIA_EDIT_LINK_REL) + getTitle(field));
+ link.setHref(field.getValue().textValue());
+ link.setType(ODataLinkType.MEDIA_EDIT.toString());
+ entry.getMediaEditLinks().add(link);
+
+ if (tree.has(link.getTitle() + Constants.JSON_MEDIA_ETAG_SUFFIX)) {
+ link.setMediaETag(tree.get(link.getTitle() + Constants.JSON_MEDIA_ETAG_SUFFIX).asText());
+ toRemove.add(link.getTitle() + Constants.JSON_MEDIA_ETAG_SUFFIX);
+ }
+
+ toRemove.add(field.getKey());
+ toRemove.add(setInline(field.getKey(), Constants.JSON_MEDIAEDIT_LINK_SUFFIX, tree, parser.getCodec(), link));
+ } else if (field.getKey().endsWith(Constants.JSON_MEDIA_CONTENT_TYPE)) {
+ final String linkTitle = getTitle(field);
+ for (Link link : entry.getMediaEditLinks()) {
+ if (linkTitle.equals(link.getTitle())) {
+ ((LinkImpl) link).setType(field.getValue().asText());
+ }
+ }
+ toRemove.add(field.getKey());
+ } else if (field.getKey().charAt(0) == '#') {
+ final ODataOperation operation = new ODataOperation();
+ operation.setMetadataAnchor(field.getKey());
+
+ final ObjectNode opNode = (ObjectNode) tree.get(field.getKey());
+ operation.setTitle(opNode.get(Constants.ATTR_TITLE).asText());
+ operation.setTarget(URI.create(opNode.get(Constants.ATTR_TARGET).asText()));
+
+ entry.getOperations().add(operation);
+
+ toRemove.add(field.getKey());
+ }
+ }
+ tree.remove(toRemove);
+
+ String type = null;
+ for (final Iterator<Map.Entry<String, JsonNode>> itor = tree.fields(); itor.hasNext();) {
+ final Map.Entry<String, JsonNode> field = itor.next();
+
+ if (type == null && field.getKey().endsWith(Constants.JSON_TYPE_SUFFIX)) {
+ type = field.getValue().asText();
+ } else {
+ final JSONPropertyImpl property = new JSONPropertyImpl();
+ property.setName(field.getKey());
+ property.setType(type);
+ type = null;
+
+ value(property, field.getValue());
+ entry.getProperties().add(property);
+ }
+ }
+
+ return entry;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata4/blob/fac84b3e/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONEntryImpl.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONEntryImpl.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONEntryImpl.java
new file mode 100644
index 0000000..765c18a
--- /dev/null
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONEntryImpl.java
@@ -0,0 +1,92 @@
+/*
+ * 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.olingo.commons.core.data;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import java.net.URI;
+import java.text.ParseException;
+import org.apache.olingo.commons.api.Constants;
+
+/**
+ * A single entry, represented via JSON.
+ */
+@JsonSerialize(using = JSONEntrySerializer.class)
+@JsonDeserialize(using = JSONEntryDeserializer.class)
+public class JSONEntryImpl extends AbstractEntry {
+
+ private static final long serialVersionUID = -5275365545400797758L;
+
+ private URI metadata;
+
+ private String mediaETag;
+
+ public void setId(final String id) throws ParseException {
+ this.setCommonProperty("id", id);
+ }
+
+ @Override
+ public URI getBaseURI() {
+ URI baseURI = null;
+ if (metadata != null) {
+ final String metadataURI = getMetadata().toASCIIString();
+ baseURI = URI.create(metadataURI.substring(0, metadataURI.indexOf(Constants.METADATA)));
+ }
+
+ return baseURI;
+ }
+
+ /**
+ * Gets the metadata URI.
+ *
+ * @return the metadata URI
+ */
+ public URI getMetadata() {
+ return metadata;
+ }
+
+ /**
+ * Sets the metadata URI.
+ *
+ * @param metadata metadata URI.
+ */
+ public void setMetadata(final URI metadata) {
+ this.metadata = metadata;
+ }
+
+ /**
+ * The odata.mediaEtag annotation MAY be included; its value MUST be the ETag of the binary stream represented by this
+ * media entity or named stream property.
+ *
+ * @return odata.mediaEtag annotation value.
+ */
+ public String getMediaETag() {
+ return mediaETag;
+ }
+
+ /**
+ * The odata.mediaEtag annotation MAY be included; its value MUST be the ETag of the binary stream represented by this
+ * media entity or named stream property.
+ *
+ * @param eTag odata.mediaEtag annotation value.
+ */
+ public void setMediaETag(final String eTag) {
+ this.mediaETag = eTag;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata4/blob/fac84b3e/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONEntrySerializer.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONEntrySerializer.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONEntrySerializer.java
new file mode 100644
index 0000000..4041748
--- /dev/null
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONEntrySerializer.java
@@ -0,0 +1,120 @@
+/*
+ * 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.olingo.commons.core.data;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.olingo.commons.api.Constants;
+import org.apache.olingo.commons.api.data.Entry;
+import org.apache.olingo.commons.api.data.Link;
+import org.apache.olingo.commons.api.data.Property;
+import org.apache.olingo.commons.api.domain.ODataLinkType;
+
+/**
+ * Writes out JSON string from an entry.
+ */
+public class JSONEntrySerializer extends AbstractJsonSerializer<JSONEntryImpl> {
+
+ @Override
+ protected void doSerialize(final JSONEntryImpl entry, final JsonGenerator jgen, final SerializerProvider provider)
+ throws IOException, JsonProcessingException {
+
+ jgen.writeStartObject();
+
+ if (entry.getMetadata() != null) {
+ jgen.writeStringField(Constants.JSON_METADATA, entry.getMetadata().toASCIIString());
+ }
+ if (entry.getId() != null) {
+ jgen.writeStringField(Constants.JSON_ID, entry.getId());
+ }
+
+ final Map<String, List<String>> entitySetLinks = new HashMap<String, List<String>>();
+
+ for (Link link : entry.getNavigationLinks()) {
+ ODataLinkType type = null;
+ try {
+ type = ODataLinkType.fromString(version, link.getRel(), link.getType());
+ } catch (IllegalArgumentException e) {
+ // ignore
+ }
+
+ if (type == ODataLinkType.ENTITY_SET_NAVIGATION) {
+ final List<String> uris;
+ if (entitySetLinks.containsKey(link.getTitle())) {
+ uris = entitySetLinks.get(link.getTitle());
+ } else {
+ uris = new ArrayList<String>();
+ entitySetLinks.put(link.getTitle(), uris);
+ }
+ uris.add(link.getHref());
+ } else {
+ if (StringUtils.isNotBlank(link.getHref())) {
+ jgen.writeStringField(link.getTitle() + Constants.JSON_BIND_LINK_SUFFIX, link.getHref());
+ }
+ }
+
+ if (link.getInlineEntry() != null) {
+ jgen.writeObjectField(link.getTitle(), link.getInlineEntry());
+ } else if (link.getInlineFeed() != null) {
+ jgen.writeArrayFieldStart(link.getTitle());
+ for (Entry subEntry : link.getInlineFeed().getEntries()) {
+ jgen.writeObject(subEntry);
+ }
+ jgen.writeEndArray();
+ }
+ }
+ for (Map.Entry<String, List<String>> entitySetLink : entitySetLinks.entrySet()) {
+ jgen.writeArrayFieldStart(entitySetLink.getKey() + Constants.JSON_BIND_LINK_SUFFIX);
+ for (String uri : entitySetLink.getValue()) {
+ jgen.writeString(uri);
+ }
+ jgen.writeEndArray();
+ }
+
+ for (Link link : entry.getMediaEditLinks()) {
+ if (link.getTitle() == null) {
+ jgen.writeStringField(Constants.JSON_MEDIAEDIT_LINK, link.getHref());
+ }
+
+ if (link.getInlineEntry() != null) {
+ jgen.writeObjectField(link.getTitle(), link.getInlineEntry());
+ }
+ if (link.getInlineFeed() != null) {
+ jgen.writeArrayFieldStart(link.getTitle());
+ for (Entry subEntry : link.getInlineFeed().getEntries()) {
+ jgen.writeObject(subEntry);
+ }
+ jgen.writeEndArray();
+ }
+ }
+
+ for (Property property : entry.getProperties()) {
+ property(jgen, property, property.getName());
+ }
+
+ jgen.writeEndObject();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata4/blob/fac84b3e/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONErrorBundle.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONErrorBundle.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONErrorBundle.java
new file mode 100644
index 0000000..433b754
--- /dev/null
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONErrorBundle.java
@@ -0,0 +1,50 @@
+/*
+ * 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.olingo.commons.core.data;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * This class represents a bundle for an OData error returned as JSON.
+ */
+public class JSONErrorBundle extends AbstractPayloadObject {
+
+ private static final long serialVersionUID = -4784910226259754450L;
+
+ @JsonProperty("odata.error")
+ private JSONErrorImpl error;
+
+ /**
+ * Gets error.
+ *
+ * @return OData error object.
+ */
+ public JSONErrorImpl getError() {
+ return error;
+ }
+
+ /**
+ * Sets error.
+ *
+ * @param error OData error object.
+ */
+ public void setError(final JSONErrorImpl error) {
+ this.error = error;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata4/blob/fac84b3e/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONErrorImpl.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONErrorImpl.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONErrorImpl.java
new file mode 100644
index 0000000..4c6cb4a
--- /dev/null
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONErrorImpl.java
@@ -0,0 +1,237 @@
+/*
+ * 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.olingo.commons.core.data;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.apache.olingo.commons.api.domain.ODataError;
+
+/**
+ * This class represents an OData error returned as JSON.
+ */
+public class JSONErrorImpl extends AbstractPayloadObject implements ODataError {
+
+ private static final long serialVersionUID = -3476499168507242932L;
+
+ /**
+ * Error message.
+ */
+ public static class Message extends AbstractPayloadObject {
+
+ private static final long serialVersionUID = 2577818040815637859L;
+
+ private String lang;
+
+ private String value;
+
+ /**
+ * Gets language.
+ *
+ * @return language.
+ */
+ public String getLang() {
+ return lang;
+ }
+
+ /**
+ * Sets language.
+ *
+ * @param lang language.
+ */
+ public void setLang(final String lang) {
+ this.lang = lang;
+ }
+
+ /**
+ * Gets message.
+ *
+ * @return message.
+ */
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * Sets message.
+ *
+ * @param value message.
+ */
+ public void setValue(final String value) {
+ this.value = value;
+ }
+ }
+
+ /**
+ * Inner error.
+ */
+ static class InnerError extends AbstractPayloadObject {
+
+ private static final long serialVersionUID = -3920947476143537640L;
+
+ private String message;
+
+ private String type;
+
+ private String stacktrace;
+
+ private InnerError internalexception;
+
+ /**
+ * Gets inner message.
+ *
+ * @return message.
+ */
+ public String getMessage() {
+ return message;
+ }
+
+ /**
+ * Sets inner message.
+ *
+ * @param message message.
+ */
+ public void setMessage(final String message) {
+ this.message = message;
+ }
+
+ /**
+ * Gets type.
+ *
+ * @return type.
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * Sets type.
+ *
+ * @param type type.
+ */
+ public void setType(final String type) {
+ this.type = type;
+ }
+
+ /**
+ * Gets stack-trace.
+ *
+ * @return stack-trace.
+ */
+ public String getStacktrace() {
+ return stacktrace;
+ }
+
+ /**
+ * Sets stack-trace.
+ *
+ * @param stacktrace stack-trace.
+ */
+ public void setStacktrace(final String stacktrace) {
+ this.stacktrace = stacktrace;
+ }
+
+ public InnerError getInternalexception() {
+ return internalexception;
+ }
+
+ public void setInternalexception(final InnerError internalexception) {
+ this.internalexception = internalexception;
+ }
+ }
+
+ private String code;
+
+ @JsonProperty(value = "message")
+ private Message message;
+
+ @JsonProperty(value = "innererror", required = false)
+ private InnerError innererror;
+
+ /**
+ * {@inheritDoc }
+ */
+ @Override
+ public String getCode() {
+ return code;
+ }
+
+ /**
+ * Sets error code.
+ *
+ * @param code error code.
+ */
+ public void setCode(final String code) {
+ this.code = code;
+ }
+
+ /**
+ * {@inheritDoc }
+ */
+ @JsonIgnore
+ @Override
+ public String getMessageLang() {
+ return this.message == null ? null : this.message.getLang();
+ }
+
+ /**
+ * {@inheritDoc }
+ */
+ @JsonIgnore
+ @Override
+ public String getMessageValue() {
+ return this.message == null ? null : this.message.getValue();
+ }
+
+ /**
+ * Sets the value of the message property.
+ *
+ * @param value allowed object is {@link Error.Message }
+ *
+ */
+ public void setMessage(final Message value) {
+ this.message = value;
+ }
+
+ /**
+ * {@inheritDoc }
+ */
+ @JsonIgnore
+ @Override
+ public String getInnerErrorMessage() {
+ return this.innererror == null ? null : this.innererror.getMessage();
+ }
+
+ /**
+ * {@inheritDoc }
+ */
+ @JsonIgnore
+ @Override
+ public String getInnerErrorType() {
+ return this.innererror == null ? null : this.innererror.getType();
+ }
+
+ /**
+ * {@inheritDoc }
+ */
+ @JsonIgnore
+ @Override
+ public String getInnerErrorStacktrace() {
+ return this.innererror == null ? null : this.innererror.getStacktrace();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata4/blob/fac84b3e/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONFeedDeserializer.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONFeedDeserializer.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONFeedDeserializer.java
new file mode 100644
index 0000000..81a8d47
--- /dev/null
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONFeedDeserializer.java
@@ -0,0 +1,68 @@
+/*
+ * 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.olingo.commons.core.data;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import java.io.IOException;
+import java.net.URI;
+import java.util.Iterator;
+import org.apache.olingo.commons.api.Constants;
+
+/**
+ * Reads JSON string into a feed.
+ * <br/>
+ * If metadata information is available, the corresponding entry fields and content will be populated.
+ */
+public class JSONFeedDeserializer extends AbstractJsonDeserializer<JSONFeedImpl> {
+
+ @Override
+ protected JSONFeedImpl doDeserialize(final JsonParser parser, final DeserializationContext ctxt)
+ throws IOException, JsonProcessingException {
+
+ final ObjectNode tree = (ObjectNode) parser.getCodec().readTree(parser);
+
+ if (!tree.has(Constants.JSON_VALUE)) {
+ return null;
+ }
+
+ final JSONFeedImpl feed = new JSONFeedImpl();
+
+ if (tree.hasNonNull(Constants.JSON_METADATA)) {
+ feed.setMetadata(URI.create(tree.get(Constants.JSON_METADATA).textValue()));
+ }
+ if (tree.hasNonNull(Constants.JSON_COUNT)) {
+ feed.setCount(tree.get(Constants.JSON_COUNT).asInt());
+ }
+ if (tree.hasNonNull(Constants.JSON_NEXT_LINK)) {
+ feed.setNext(URI.create(tree.get(Constants.JSON_NEXT_LINK).textValue()));
+ }
+
+ if (tree.hasNonNull(Constants.JSON_VALUE)) {
+ for (final Iterator<JsonNode> itor = tree.get(Constants.JSON_VALUE).iterator(); itor.hasNext();) {
+ feed.getEntries().add(itor.next().traverse(parser.getCodec()).readValueAs(JSONEntryImpl.class));
+ }
+ }
+
+ return feed;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata4/blob/fac84b3e/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONFeedImpl.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONFeedImpl.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONFeedImpl.java
new file mode 100644
index 0000000..f41e21c
--- /dev/null
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONFeedImpl.java
@@ -0,0 +1,113 @@
+/*
+ * 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.olingo.commons.core.data;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.olingo.commons.api.data.Entry;
+import org.apache.olingo.commons.api.data.Feed;
+import org.apache.olingo.commons.api.Constants;
+
+/**
+ * List of entries, represented via JSON.
+ *
+ * @see JSONEntry
+ */
+@JsonDeserialize(using = JSONFeedDeserializer.class)
+@JsonSerialize(using = JSONFeedSerializer.class)
+public class JSONFeedImpl extends AbstractPayloadObject implements Feed {
+
+ private static final long serialVersionUID = -3576372289800799417L;
+
+ private String id;
+
+ private URI metadata;
+
+ private Integer count;
+
+ private final List<Entry> entries = new ArrayList<Entry>();
+
+ private String next;
+
+ @Override
+ public URI getBaseURI() {
+ URI baseURI = null;
+ if (metadata != null) {
+ final String metadataURI = getMetadata().toASCIIString();
+ baseURI = URI.create(metadataURI.substring(0, metadataURI.indexOf(Constants.METADATA)));
+ }
+
+ return baseURI;
+ }
+
+ /**
+ * Gets the metadata URI.
+ *
+ * @return the metadata URI
+ */
+ public URI getMetadata() {
+ return metadata;
+ }
+
+ /**
+ * Sets the metadata URI.
+ *
+ * @param metadata metadata URI.
+ */
+ public void setMetadata(final URI metadata) {
+ this.metadata = metadata;
+ }
+
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ public void setId(final String id) {
+ this.id = id;
+ }
+
+ @Override
+ public Integer getCount() {
+ return count;
+ }
+
+ @Override
+ public void setCount(final Integer count) {
+ this.count = count;
+ }
+
+ @Override
+ public List<Entry> getEntries() {
+ return entries;
+ }
+
+ @Override
+ public void setNext(final URI next) {
+ this.next = next.toASCIIString();
+ }
+
+ @Override
+ public URI getNext() {
+ return next == null ? null : URI.create(next);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata4/blob/fac84b3e/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONFeedSerializer.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONFeedSerializer.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONFeedSerializer.java
new file mode 100644
index 0000000..25a7358
--- /dev/null
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONFeedSerializer.java
@@ -0,0 +1,57 @@
+/*
+ * 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.olingo.commons.core.data;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import java.io.IOException;
+import org.apache.olingo.commons.api.Constants;
+import org.apache.olingo.commons.api.data.Entry;
+
+public class JSONFeedSerializer extends AbstractJsonSerializer<JSONFeedImpl> {
+
+ @Override
+ protected void doSerialize(final JSONFeedImpl feed, final JsonGenerator jgen, final SerializerProvider provider)
+ throws IOException, JsonProcessingException {
+
+ jgen.writeStartObject();
+
+ if (feed.getMetadata() != null) {
+ jgen.writeStringField(Constants.JSON_METADATA, feed.getMetadata().toASCIIString());
+ }
+ if (feed.getId() != null) {
+ jgen.writeStringField(Constants.JSON_ID, feed.getId());
+ }
+ if (feed.getCount() != null) {
+ jgen.writeNumberField(Constants.JSON_COUNT, feed.getCount());
+ }
+ if (feed.getNext() != null) {
+ jgen.writeStringField(Constants.JSON_NEXT_LINK, feed.getNext().toASCIIString());
+ }
+
+ jgen.writeArrayFieldStart(Constants.JSON_VALUE);
+ for (Entry entry : feed.getEntries()) {
+ jgen.writeObject(entry);
+ }
+
+ jgen.writeEndArray();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata4/blob/fac84b3e/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONGeoValueDeserializer.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONGeoValueDeserializer.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONGeoValueDeserializer.java
new file mode 100644
index 0000000..f1863a7
--- /dev/null
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONGeoValueDeserializer.java
@@ -0,0 +1,274 @@
+/*
+ * 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.olingo.commons.core.data;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import org.apache.olingo.commons.api.Constants;
+import org.apache.olingo.commons.api.data.GeoUtils;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
+import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
+import org.apache.olingo.commons.api.edm.geo.Geospatial;
+import org.apache.olingo.commons.api.edm.geo.GeospatialCollection;
+import org.apache.olingo.commons.api.edm.geo.LineString;
+import org.apache.olingo.commons.api.edm.geo.MultiLineString;
+import org.apache.olingo.commons.api.edm.geo.MultiPoint;
+import org.apache.olingo.commons.api.edm.geo.MultiPolygon;
+import org.apache.olingo.commons.api.edm.geo.Point;
+import org.apache.olingo.commons.api.edm.geo.Polygon;
+import org.apache.olingo.commons.core.edm.EdmTypeInfo;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmDouble;
+
+class JSONGeoValueDeserializer {
+
+ private final ODataServiceVersion version;
+
+ public JSONGeoValueDeserializer(final ODataServiceVersion version) {
+ this.version = version;
+ }
+
+ private Point point(final Iterator<JsonNode> itor, final EdmPrimitiveTypeKind type, final String crs) {
+ Point point = null;
+
+ if (itor.hasNext()) {
+ point = new Point(GeoUtils.getDimension(type), crs);
+ try {
+ point.setX(EdmDouble.getInstance().valueOfString(itor.next().asText(), null, null,
+ Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null, Double.class));
+ point.setY(EdmDouble.getInstance().valueOfString(itor.next().asText(), null, null,
+ Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null, Double.class));
+ } catch (EdmPrimitiveTypeException e) {
+ throw new IllegalArgumentException("While deserializing point coordinates as double", e);
+ }
+ }
+
+ return point;
+ }
+
+ private MultiPoint multipoint(final Iterator<JsonNode> itor, final EdmPrimitiveTypeKind type,
+ final String crs) {
+
+ MultiPoint multiPoint = null;
+
+ if (itor.hasNext()) {
+ final List<Point> points = new ArrayList<Point>();
+ while (itor.hasNext()) {
+ final Iterator<JsonNode> mpItor = itor.next().elements();
+ points.add(point(mpItor, type, crs));
+ }
+ multiPoint = new MultiPoint(GeoUtils.getDimension(type), crs, points);
+ } else {
+ multiPoint = new MultiPoint(GeoUtils.getDimension(type), crs, Collections.<Point>emptyList());
+ }
+
+ return multiPoint;
+ }
+
+ private LineString lineString(final Iterator<JsonNode> itor, final EdmPrimitiveTypeKind type,
+ final String crs) {
+
+ LineString lineString = null;
+
+ if (itor.hasNext()) {
+ final List<Point> points = new ArrayList<Point>();
+ while (itor.hasNext()) {
+ final Iterator<JsonNode> mpItor = itor.next().elements();
+ points.add(point(mpItor, type, crs));
+ }
+ lineString = new LineString(GeoUtils.getDimension(type), crs, points);
+ } else {
+ lineString = new LineString(GeoUtils.getDimension(type), crs, Collections.<Point>emptyList());
+ }
+
+ return lineString;
+ }
+
+ private MultiLineString multiLineString(final Iterator<JsonNode> itor, final EdmPrimitiveTypeKind type,
+ final String crs) {
+
+ MultiLineString multiLineString = null;
+
+ if (itor.hasNext()) {
+ final List<LineString> lineStrings = new ArrayList<LineString>();
+ while (itor.hasNext()) {
+ final Iterator<JsonNode> mlsItor = itor.next().elements();
+ lineStrings.add(lineString(mlsItor, type, crs));
+ }
+ multiLineString = new MultiLineString(GeoUtils.getDimension(type), crs, lineStrings);
+ } else {
+ multiLineString = new MultiLineString(GeoUtils.getDimension(type), crs, Collections.<LineString>emptyList());
+ }
+
+ return multiLineString;
+ }
+
+ private Polygon polygon(final Iterator<JsonNode> itor, final EdmPrimitiveTypeKind type,
+ final String crs) {
+
+ List<Point> extPoints = null;
+ if (itor.hasNext()) {
+ final Iterator<JsonNode> extItor = itor.next().elements();
+ if (extItor.hasNext()) {
+ extPoints = new ArrayList<Point>();
+ while (extItor.hasNext()) {
+ final Iterator<JsonNode> mpItor = extItor.next().elements();
+ extPoints.add(point(mpItor, type, crs));
+ }
+ }
+ }
+
+ List<Point> intPoints = null;
+ if (itor.hasNext()) {
+ final Iterator<JsonNode> intItor = itor.next().elements();
+ if (intItor.hasNext()) {
+ intPoints = new ArrayList<Point>();
+ while (intItor.hasNext()) {
+ final Iterator<JsonNode> mpItor = intItor.next().elements();
+ intPoints.add(point(mpItor, type, crs));
+ }
+ }
+ }
+
+ return new Polygon(GeoUtils.getDimension(type), crs, intPoints, extPoints);
+ }
+
+ private MultiPolygon multiPolygon(final Iterator<JsonNode> itor, final EdmPrimitiveTypeKind type,
+ final String crs) {
+
+ MultiPolygon multiPolygon = null;
+
+ if (itor.hasNext()) {
+ final List<Polygon> polygons = new ArrayList<Polygon>();
+ while (itor.hasNext()) {
+ final Iterator<JsonNode> mpItor = itor.next().elements();
+ polygons.add(polygon(mpItor, type, crs));
+ }
+ multiPolygon = new MultiPolygon(GeoUtils.getDimension(type), crs, polygons);
+ } else {
+ multiPolygon = new MultiPolygon(GeoUtils.getDimension(type), crs, Collections.<Polygon>emptyList());
+ }
+
+ return multiPolygon;
+ }
+
+ private GeospatialCollection collection(final Iterator<JsonNode> itor, final EdmPrimitiveTypeKind type,
+ final String crs) {
+
+ GeospatialCollection collection = null;
+
+ if (itor.hasNext()) {
+ final List<Geospatial> geospatials = new ArrayList<Geospatial>();
+
+ while (itor.hasNext()) {
+ final JsonNode geo = itor.next();
+ final String collItemType = geo.get(Constants.ATTR_TYPE).asText();
+ final String callAsType;
+ if (EdmPrimitiveTypeKind.GeographyCollection.name().equals(collItemType)
+ || EdmPrimitiveTypeKind.GeometryCollection.name().equals(collItemType)) {
+
+ callAsType = collItemType;
+ } else {
+ callAsType = (type == EdmPrimitiveTypeKind.GeographyCollection ? "Geography" : "Geometry")
+ + collItemType;
+ }
+
+ geospatials.add(deserialize(geo, new EdmTypeInfo.Builder().setTypeExpression(callAsType).build()));
+ }
+
+ collection = new GeospatialCollection(GeoUtils.getDimension(type), crs, geospatials);
+ } else {
+ collection = new GeospatialCollection(GeoUtils.getDimension(type), crs, Collections.<Geospatial>emptyList());
+ }
+
+ return collection;
+ }
+
+ public Geospatial deserialize(final JsonNode node, final EdmTypeInfo typeInfo) {
+ final EdmPrimitiveTypeKind actualType;
+ if ((typeInfo.getPrimitiveTypeKind() == EdmPrimitiveTypeKind.Geography
+ || typeInfo.getPrimitiveTypeKind() == EdmPrimitiveTypeKind.Geometry)
+ && node.has(Constants.ATTR_TYPE)) {
+
+ String nodeType = node.get(Constants.ATTR_TYPE).asText();
+ if (nodeType.startsWith("Geo")) {
+ final int yIdx = nodeType.indexOf('y');
+ nodeType = nodeType.substring(yIdx + 1);
+ }
+ actualType = EdmPrimitiveTypeKind.valueOfFQN(version, typeInfo.getFullQualifiedName().toString() + nodeType);
+ } else {
+ actualType = typeInfo.getPrimitiveTypeKind();
+ }
+
+ final Iterator<JsonNode> cooItor = node.has(Constants.JSON_COORDINATES)
+ ? node.get(Constants.JSON_COORDINATES).elements()
+ : Collections.<JsonNode>emptyList().iterator();
+
+ String crs = null;
+ if (node.has(Constants.JSON_CRS)) {
+ crs = node.get(Constants.JSON_CRS).get(Constants.PROPERTIES).get(Constants.JSON_NAME).asText().split(":")[1];
+ }
+
+ Geospatial value = null;
+ switch (actualType) {
+ case GeographyPoint:
+ case GeometryPoint:
+ value = point(cooItor, actualType, crs);
+ break;
+
+ case GeographyMultiPoint:
+ case GeometryMultiPoint:
+ value = multipoint(cooItor, actualType, crs);
+ break;
+
+ case GeographyLineString:
+ case GeometryLineString:
+ value = lineString(cooItor, actualType, crs);
+ break;
+
+ case GeographyMultiLineString:
+ case GeometryMultiLineString:
+ value = multiLineString(cooItor, actualType, crs);
+ break;
+
+ case GeographyPolygon:
+ case GeometryPolygon:
+ value = polygon(cooItor, actualType, crs);
+ break;
+
+ case GeographyMultiPolygon:
+ case GeometryMultiPolygon:
+ value = multiPolygon(cooItor, actualType, crs);
+ break;
+
+ case GeographyCollection:
+ case GeometryCollection:
+ value = collection(node.get(Constants.JSON_GEOMETRIES).elements(), actualType, crs);
+ break;
+
+ default:
+ }
+
+ return value;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata4/blob/fac84b3e/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONGeoValueSerializer.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONGeoValueSerializer.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONGeoValueSerializer.java
new file mode 100644
index 0000000..95c30d4
--- /dev/null
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONGeoValueSerializer.java
@@ -0,0 +1,183 @@
+/*
+ * 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.olingo.commons.core.data;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import java.io.IOException;
+import java.util.Iterator;
+import org.apache.olingo.commons.api.Constants;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
+import org.apache.olingo.commons.api.edm.geo.ComposedGeospatial;
+import org.apache.olingo.commons.api.edm.geo.Geospatial;
+import org.apache.olingo.commons.api.edm.geo.GeospatialCollection;
+import org.apache.olingo.commons.api.edm.geo.LineString;
+import org.apache.olingo.commons.api.edm.geo.MultiLineString;
+import org.apache.olingo.commons.api.edm.geo.MultiPoint;
+import org.apache.olingo.commons.api.edm.geo.MultiPolygon;
+import org.apache.olingo.commons.api.edm.geo.Point;
+import org.apache.olingo.commons.api.edm.geo.Polygon;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmDouble;
+
+class JSONGeoValueSerializer {
+
+ private void crs(final JsonGenerator jgen, final String crs) throws IOException {
+ jgen.writeObjectFieldStart(Constants.JSON_CRS);
+ jgen.writeStringField(Constants.ATTR_TYPE, Constants.JSON_NAME);
+ jgen.writeObjectFieldStart(Constants.PROPERTIES);
+ jgen.writeStringField(Constants.JSON_NAME, "EPSG:" + crs);
+ jgen.writeEndObject();
+ jgen.writeEndObject();
+ }
+
+ private void point(final JsonGenerator jgen, final Point point) throws IOException {
+ try {
+ jgen.writeNumber(EdmDouble.getInstance().valueToString(point.getX(), null, null,
+ Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null));
+ jgen.writeNumber(EdmDouble.getInstance().valueToString(point.getY(), null, null,
+ Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null));
+ } catch (EdmPrimitiveTypeException e) {
+ throw new IllegalArgumentException("While serializing point coordinates as double", e);
+ }
+ }
+
+ private void multipoint(final JsonGenerator jgen, final MultiPoint multiPoint) throws IOException {
+ for (final Iterator<Point> itor = multiPoint.iterator(); itor.hasNext();) {
+ jgen.writeStartArray();
+ point(jgen, itor.next());
+ jgen.writeEndArray();
+ }
+ }
+
+ private void lineString(final JsonGenerator jgen, final ComposedGeospatial<Point> lineString) throws IOException {
+ for (final Iterator<Point> itor = lineString.iterator(); itor.hasNext();) {
+ jgen.writeStartArray();
+ point(jgen, itor.next());
+ jgen.writeEndArray();
+ }
+ }
+
+ private void multiLineString(final JsonGenerator jgen, final MultiLineString multiLineString) throws IOException {
+ for (final Iterator<LineString> itor = multiLineString.iterator(); itor.hasNext();) {
+ jgen.writeStartArray();
+ lineString(jgen, itor.next());
+ jgen.writeEndArray();
+ }
+ }
+
+ private void polygon(final JsonGenerator jgen, final Polygon polygon) throws IOException {
+ if (!polygon.getExterior().isEmpty()) {
+ jgen.writeStartArray();
+ lineString(jgen, polygon.getExterior());
+ jgen.writeEndArray();
+ }
+ if (!polygon.getInterior().isEmpty()) {
+ jgen.writeStartArray();
+ lineString(jgen, polygon.getInterior());
+ jgen.writeEndArray();
+ }
+ }
+
+ private void multiPolygon(final JsonGenerator jgen, final MultiPolygon multiPolygon) throws IOException {
+ for (final Iterator<Polygon> itor = multiPolygon.iterator(); itor.hasNext();) {
+ final Polygon polygon = itor.next();
+ jgen.writeStartArray();
+ polygon(jgen, polygon);
+ jgen.writeEndArray();
+ }
+ }
+
+ private void collection(final JsonGenerator jgen, final GeospatialCollection collection) throws IOException {
+ jgen.writeArrayFieldStart(Constants.JSON_GEOMETRIES);
+ for (final Iterator<Geospatial> itor = collection.iterator(); itor.hasNext();) {
+ jgen.writeStartObject();
+ serialize(jgen, itor.next());
+ jgen.writeEndObject();
+ }
+ jgen.writeEndArray();
+ }
+
+ public void serialize(final JsonGenerator jgen, final Geospatial value) throws IOException {
+ if (value.getEdmPrimitiveTypeKind().equals(EdmPrimitiveTypeKind.GeographyCollection)
+ || value.getEdmPrimitiveTypeKind().equals(EdmPrimitiveTypeKind.GeometryCollection)) {
+
+ jgen.writeStringField(Constants.ATTR_TYPE, EdmPrimitiveTypeKind.GeometryCollection.name());
+ } else {
+ final int yIdx = value.getEdmPrimitiveTypeKind().name().indexOf('y');
+ final String itemType = value.getEdmPrimitiveTypeKind().name().substring(yIdx + 1);
+ jgen.writeStringField(Constants.ATTR_TYPE, itemType);
+ }
+
+ switch (value.getEdmPrimitiveTypeKind()) {
+ case GeographyPoint:
+ case GeometryPoint:
+ jgen.writeArrayFieldStart(Constants.JSON_COORDINATES);
+ point(jgen, (Point) value);
+ jgen.writeEndArray();
+ break;
+
+ case GeographyMultiPoint:
+ case GeometryMultiPoint:
+ jgen.writeArrayFieldStart(Constants.JSON_COORDINATES);
+ multipoint(jgen, (MultiPoint) value);
+ jgen.writeEndArray();
+ break;
+
+ case GeographyLineString:
+ case GeometryLineString:
+ jgen.writeArrayFieldStart(Constants.JSON_COORDINATES);
+ lineString(jgen, (LineString) value);
+ jgen.writeEndArray();
+ break;
+
+ case GeographyMultiLineString:
+ case GeometryMultiLineString:
+ jgen.writeArrayFieldStart(Constants.JSON_COORDINATES);
+ multiLineString(jgen, (MultiLineString) value);
+ jgen.writeEndArray();
+ break;
+
+ case GeographyPolygon:
+ case GeometryPolygon:
+ jgen.writeArrayFieldStart(Constants.JSON_COORDINATES);
+ polygon(jgen, (Polygon) value);
+ jgen.writeEndArray();
+ break;
+
+ case GeographyMultiPolygon:
+ case GeometryMultiPolygon:
+ jgen.writeArrayFieldStart(Constants.JSON_COORDINATES);
+ multiPolygon(jgen, (MultiPolygon) value);
+ jgen.writeEndArray();
+ break;
+
+ case GeographyCollection:
+ case GeometryCollection:
+ collection(jgen, (GeospatialCollection) value);
+ break;
+
+ default:
+ }
+
+ if (value.getCrs() != null) {
+ crs(jgen, value.getCrs());
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata4/blob/fac84b3e/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONPropertyDeserializer.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONPropertyDeserializer.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONPropertyDeserializer.java
new file mode 100644
index 0000000..b68d998
--- /dev/null
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONPropertyDeserializer.java
@@ -0,0 +1,71 @@
+/*
+ * 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.olingo.commons.core.data;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import java.io.IOException;
+import java.net.URI;
+import org.apache.olingo.commons.api.Constants;
+
+/**
+ * Parse JSON string into <tt>JSONPropertyImpl</tt>.
+ *
+ * @see JSONPropertyImpl
+ */
+public class JSONPropertyDeserializer extends AbstractJsonDeserializer<JSONPropertyImpl> {
+
+ @Override
+ protected JSONPropertyImpl doDeserialize(final JsonParser parser, final DeserializationContext ctxt)
+ throws IOException, JsonProcessingException {
+
+ final ObjectNode tree = (ObjectNode) parser.getCodec().readTree(parser);
+
+ final JSONPropertyImpl property = new JSONPropertyImpl();
+
+ if (tree.hasNonNull(Constants.JSON_METADATA)) {
+ property.setMetadata(URI.create(tree.get(Constants.JSON_METADATA).textValue()));
+ tree.remove(Constants.JSON_METADATA);
+ }
+
+ if (property.getMetadata() != null) {
+ final String metadataURI = property.getMetadata().toASCIIString();
+ final int dashIdx = metadataURI.lastIndexOf('#');
+ if (dashIdx != -1) {
+ property.setType(metadataURI.substring(dashIdx + 1));
+ }
+ }
+
+ if (tree.has(Constants.JSON_TYPE) && property.getType() == null) {
+ property.setType(tree.get(Constants.JSON_TYPE).asText());
+ }
+
+ if (tree.has(Constants.JSON_NULL) && tree.get(Constants.JSON_NULL).asBoolean()) {
+ property.setValue(new NullValueImpl());
+ }
+
+ if (property.getValue() == null) {
+ value(property, tree.has(Constants.JSON_VALUE) ? tree.get(Constants.JSON_VALUE) : tree);
+ }
+
+ return property;
+ }
+}