[OLINGO-530] Entity and EntitySet deserialization
This commit is contained in:
parent
ab39763f3e
commit
2ac6ba18bb
|
@ -22,7 +22,9 @@ import java.util.List;
|
|||
|
||||
import org.apache.olingo.commons.api.ODataRuntimeException;
|
||||
import org.apache.olingo.commons.api.format.ODataFormat;
|
||||
import org.apache.olingo.server.api.deserializer.DeserializerException;
|
||||
import org.apache.olingo.server.api.deserializer.FixedFormatDeserializer;
|
||||
import org.apache.olingo.server.api.deserializer.ODataDeserializer;
|
||||
import org.apache.olingo.server.api.edm.provider.EdmProvider;
|
||||
import org.apache.olingo.server.api.edmx.EdmxReference;
|
||||
import org.apache.olingo.server.api.serializer.FixedFormatSerializer;
|
||||
|
@ -96,4 +98,6 @@ public abstract class OData {
|
|||
* It can be used in Processor implementations.
|
||||
*/
|
||||
public abstract UriHelper createUriHelper();
|
||||
|
||||
public abstract ODataDeserializer createDeserializer(ODataFormat format) throws DeserializerException;
|
||||
}
|
||||
|
|
|
@ -28,7 +28,18 @@ public class DeserializerException extends ODataTranslatedException {
|
|||
/** Keys for exception texts in the resource bundle. */
|
||||
public static enum MessageKeys implements MessageKey {
|
||||
NOT_IMPLEMENTED,
|
||||
IO_EXCEPTION;
|
||||
IO_EXCEPTION,
|
||||
//TODO: create texts for the following message keys:
|
||||
/** parameter: format */ UNSUPPORTED_FORMAT,
|
||||
JSON_SYNTAX_EXCEPTION,
|
||||
/** parameter: propertyName */ INVALID_NULL_PROPERTY,
|
||||
TREE_NOT_EMPTY,
|
||||
/** parameter: propertyName */ INVALID_VALUE_FOR_PROPERTY,
|
||||
/** parameter: propertyName */ INVALID_TYPE_FOR_PROPERTY,
|
||||
VALUE_ARRAY_NOT_PRESENT,
|
||||
VALUE_TAG_MUST_BE_AN_ARRAY,
|
||||
INVALID_ENTITY,
|
||||
/** parameter: navigationPropertyName */INVALID_VALUE_FOR_NAVIGATION_PROPERTY;
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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.server.api.deserializer;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.apache.olingo.commons.api.data.Entity;
|
||||
import org.apache.olingo.commons.api.data.EntitySet;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityType;
|
||||
|
||||
public interface ODataDeserializer {
|
||||
|
||||
Entity entity(InputStream stream, EdmEntityType edmEntityType) throws DeserializerException;
|
||||
|
||||
EntitySet entitySet(InputStream stream, EdmEntityType edmEntityType) throws DeserializerException;
|
||||
|
||||
}
|
|
@ -25,7 +25,9 @@ import org.apache.olingo.commons.api.format.ODataFormat;
|
|||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.ODataHttpHandler;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.deserializer.DeserializerException;
|
||||
import org.apache.olingo.server.api.deserializer.FixedFormatDeserializer;
|
||||
import org.apache.olingo.server.api.deserializer.ODataDeserializer;
|
||||
import org.apache.olingo.server.api.edm.provider.EdmProvider;
|
||||
import org.apache.olingo.server.api.edmx.EdmxReference;
|
||||
import org.apache.olingo.server.api.serializer.FixedFormatSerializer;
|
||||
|
@ -33,6 +35,7 @@ import org.apache.olingo.server.api.serializer.ODataSerializer;
|
|||
import org.apache.olingo.server.api.serializer.SerializerException;
|
||||
import org.apache.olingo.server.api.uri.UriHelper;
|
||||
import org.apache.olingo.server.core.deserializer.FixedFormatDeserializerImpl;
|
||||
import org.apache.olingo.server.core.deserializer.json.ODataJsonDeserializer;
|
||||
import org.apache.olingo.server.core.serializer.FixedFormatSerializerImpl;
|
||||
import org.apache.olingo.server.core.serializer.json.ODataJsonSerializer;
|
||||
import org.apache.olingo.server.core.serializer.xml.ODataXmlSerializerImpl;
|
||||
|
@ -84,4 +87,23 @@ public class ODataImpl extends OData {
|
|||
public UriHelper createUriHelper() {
|
||||
return new UriHelperImpl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ODataDeserializer createDeserializer(ODataFormat format) throws DeserializerException{
|
||||
ODataDeserializer serializer;
|
||||
switch (format) {
|
||||
case JSON:
|
||||
case JSON_NO_METADATA:
|
||||
case JSON_FULL_METADATA:
|
||||
serializer = new ODataJsonDeserializer();
|
||||
break;
|
||||
case XML:
|
||||
//We do not support xml deserialization right now so this mus lead to an error
|
||||
default:
|
||||
throw new DeserializerException("Unsupported format: " + format,
|
||||
SerializerException.MessageKeys.UNSUPPORTED_FORMAT, format.toString());
|
||||
}
|
||||
|
||||
return serializer;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,523 @@
|
|||
/*
|
||||
* 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.server.core.deserializer.json;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.olingo.commons.api.Constants;
|
||||
import org.apache.olingo.commons.api.data.Entity;
|
||||
import org.apache.olingo.commons.api.data.EntitySet;
|
||||
import org.apache.olingo.commons.api.data.Link;
|
||||
import org.apache.olingo.commons.api.data.Property;
|
||||
import org.apache.olingo.commons.api.data.ValueType;
|
||||
import org.apache.olingo.commons.api.domain.ODataLinkType;
|
||||
import org.apache.olingo.commons.api.edm.EdmComplexType;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityType;
|
||||
import org.apache.olingo.commons.api.edm.EdmEnumType;
|
||||
import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
|
||||
import org.apache.olingo.commons.api.edm.EdmProperty;
|
||||
import org.apache.olingo.commons.api.edm.EdmTypeDefinition;
|
||||
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
|
||||
import org.apache.olingo.commons.core.data.EntityImpl;
|
||||
import org.apache.olingo.commons.core.data.EntitySetImpl;
|
||||
import org.apache.olingo.commons.core.data.LinkImpl;
|
||||
import org.apache.olingo.commons.core.data.PropertyImpl;
|
||||
import org.apache.olingo.commons.core.edm.EdmTypeInfo;
|
||||
import org.apache.olingo.server.api.deserializer.DeserializerException;
|
||||
import org.apache.olingo.server.api.deserializer.ODataDeserializer;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import com.fasterxml.jackson.core.JsonParseException;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
|
||||
public class ODataJsonDeserializer implements ODataDeserializer {
|
||||
|
||||
@Override
|
||||
public EntitySet entitySet(InputStream stream, EdmEntityType edmEntityType) throws DeserializerException {
|
||||
try {
|
||||
JsonParser parser = new JsonFactory(new ObjectMapper()).createParser(stream);
|
||||
final ObjectNode tree = parser.getCodec().readTree(parser);
|
||||
|
||||
return consumeEntitySetNode(edmEntityType, tree);
|
||||
} catch (JsonParseException e) {
|
||||
throw new DeserializerException("An JsonParseException occourred", e,
|
||||
DeserializerException.MessageKeys.JSON_SYNTAX_EXCEPTION);
|
||||
} catch (IOException e) {
|
||||
throw new DeserializerException("An IOException occourred", e, DeserializerException.MessageKeys.IO_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
private EntitySet consumeEntitySetNode(EdmEntityType edmEntityType, final ObjectNode tree)
|
||||
throws DeserializerException {
|
||||
EntitySetImpl entitySet = new EntitySetImpl();
|
||||
// Consume entitySet annotations
|
||||
consumeODataEntitySetAnnotations(tree, entitySet);
|
||||
|
||||
// Consume entities
|
||||
JsonNode jsonNode = tree.get(Constants.VALUE);
|
||||
if (jsonNode != null) {
|
||||
if (jsonNode.isArray() == false) {
|
||||
throw new DeserializerException("The content of the value tag must be an Array but is not. ",
|
||||
DeserializerException.MessageKeys.VALUE_TAG_MUST_BE_AN_ARRAY);
|
||||
}
|
||||
|
||||
consumeEntitySetArray(entitySet, edmEntityType, jsonNode);
|
||||
tree.remove(Constants.VALUE);
|
||||
} else {
|
||||
throw new DeserializerException("Could not find value array.",
|
||||
DeserializerException.MessageKeys.VALUE_ARRAY_NOT_PRESENT);
|
||||
}
|
||||
|
||||
if (tree.size() != 0) {
|
||||
throw new DeserializerException("Tree should be empty but still has content left.",
|
||||
DeserializerException.MessageKeys.TREE_NOT_EMPTY);
|
||||
}
|
||||
return entitySet;
|
||||
}
|
||||
|
||||
private void consumeEntitySetArray(EntitySetImpl entitySet, EdmEntityType edmEntityType, JsonNode jsonNode)
|
||||
throws DeserializerException {
|
||||
Iterator<JsonNode> arrayIterator = jsonNode.iterator();
|
||||
while (arrayIterator.hasNext()) {
|
||||
JsonNode arrayElement = (JsonNode) arrayIterator.next();
|
||||
if (arrayElement.isContainerNode() && arrayElement.isArray()) {
|
||||
throw new DeserializerException("Nested Arrays and primitive values are not allowed for an entity value.",
|
||||
DeserializerException.MessageKeys.INVALID_ENTITY);
|
||||
}
|
||||
|
||||
entitySet.getEntities().add(consumeEntityNode(edmEntityType, (ObjectNode) arrayElement));
|
||||
}
|
||||
}
|
||||
|
||||
private void consumeODataEntitySetAnnotations(final ObjectNode tree, EntitySetImpl entitySet) {
|
||||
URI contextURL;
|
||||
if (tree.hasNonNull(Constants.JSON_CONTEXT)) {
|
||||
contextURL = URI.create(tree.get(Constants.JSON_CONTEXT).textValue());
|
||||
tree.remove(Constants.JSON_CONTEXT);
|
||||
} else if (tree.hasNonNull(Constants.JSON_METADATA)) {
|
||||
contextURL = URI.create(tree.get(Constants.JSON_METADATA).textValue());
|
||||
tree.remove(Constants.JSON_METADATA);
|
||||
} else {
|
||||
contextURL = null;
|
||||
}
|
||||
if (contextURL != null) {
|
||||
entitySet.setBaseURI(StringUtils.substringBefore(contextURL.toASCIIString(), Constants.METADATA));
|
||||
}
|
||||
|
||||
if (tree.hasNonNull(Constants.JSON_COUNT)) {
|
||||
entitySet.setCount(tree.get(Constants.JSON_COUNT).asInt());
|
||||
tree.remove(Constants.JSON_COUNT);
|
||||
}
|
||||
if (tree.hasNonNull(Constants.JSON_NEXT_LINK)) {
|
||||
entitySet.setNext(URI.create(tree.get(Constants.JSON_NEXT_LINK).textValue()));
|
||||
tree.remove(Constants.JSON_NEXT_LINK);
|
||||
}
|
||||
if (tree.hasNonNull(Constants.JSON_DELTA_LINK)) {
|
||||
entitySet.setDeltaLink(URI.create(tree.get(Constants.JSON_DELTA_LINK).textValue()));
|
||||
tree.remove(Constants.JSON_DELTA_LINK);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity entity(InputStream stream, EdmEntityType edmEntityType) throws DeserializerException {
|
||||
try {
|
||||
JsonParser parser = new JsonFactory(new ObjectMapper()).createParser(stream);
|
||||
final ObjectNode tree = parser.getCodec().readTree(parser);
|
||||
|
||||
return consumeEntityNode(edmEntityType, tree);
|
||||
|
||||
} catch (JsonParseException e) {
|
||||
throw new DeserializerException("An JsonParseException occourred", e,
|
||||
DeserializerException.MessageKeys.JSON_SYNTAX_EXCEPTION);
|
||||
} catch (IOException e) {
|
||||
throw new DeserializerException("An IOException occourred", e, DeserializerException.MessageKeys.IO_EXCEPTION);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Entity consumeEntityNode(EdmEntityType edmEntityType, final ObjectNode tree) throws DeserializerException {
|
||||
EntityImpl entity = new EntityImpl();
|
||||
entity.setType(edmEntityType.getFullQualifiedName().getFullQualifiedNameAsString());
|
||||
|
||||
// Check and consume all Properties
|
||||
List<String> propertyNames = edmEntityType.getPropertyNames();
|
||||
for (String propertyName : propertyNames) {
|
||||
JsonNode jsonNode = tree.get(propertyName);
|
||||
if (jsonNode != null) {
|
||||
EdmProperty edmProperty = (EdmProperty) edmEntityType.getProperty(propertyName);
|
||||
if (jsonNode.isNull() == true && edmProperty.isNullable() != null
|
||||
&& edmProperty.isNullable().booleanValue() == false) {
|
||||
throw new DeserializerException("Property: " + propertyName + " must not be null.",
|
||||
DeserializerException.MessageKeys.INVALID_NULL_PROPERTY, propertyName);
|
||||
}
|
||||
Property property = consumePropertyNode(edmProperty, jsonNode);
|
||||
entity.addProperty(property);
|
||||
tree.remove(propertyName);
|
||||
}
|
||||
}
|
||||
|
||||
// Check and consume all expanded Navigation Properties
|
||||
List<String> navigationPropertyNames = edmEntityType.getNavigationPropertyNames();
|
||||
for (String navigationPropertyName : navigationPropertyNames) {
|
||||
// read expanded navigation property
|
||||
JsonNode jsonNode = tree.get(navigationPropertyName);
|
||||
if (jsonNode != null) {
|
||||
EdmNavigationProperty edmNavigationProperty = edmEntityType.getNavigationProperty(navigationPropertyName);
|
||||
if (jsonNode.isNull() == true && edmNavigationProperty.isNullable() != null
|
||||
&& edmNavigationProperty.isNullable().booleanValue() == false) {
|
||||
throw new DeserializerException("Property: " + navigationPropertyName + " must not be null.",
|
||||
DeserializerException.MessageKeys.INVALID_NULL_PROPERTY, navigationPropertyName);
|
||||
}
|
||||
|
||||
LinkImpl link = new LinkImpl();
|
||||
link.setTitle(navigationPropertyName);
|
||||
if (jsonNode.isArray() && edmNavigationProperty.isCollection()) {
|
||||
link.setType(ODataLinkType.ENTITY_SET_NAVIGATION.toString());
|
||||
EntitySetImpl inlineEntitySet = new EntitySetImpl();
|
||||
consumeEntitySetArray(inlineEntitySet, edmNavigationProperty.getType(), jsonNode);
|
||||
link.setInlineEntitySet(inlineEntitySet);
|
||||
} else if (!jsonNode.isArray() && !jsonNode.isValueNode() && !edmNavigationProperty.isCollection()) {
|
||||
link.setType(ODataLinkType.ENTITY_NAVIGATION.toString());
|
||||
if (!jsonNode.isNull()) {
|
||||
Entity inlineEntity = consumeEntityNode(edmNavigationProperty.getType(), (ObjectNode) jsonNode);
|
||||
link.setInlineEntity(inlineEntity);
|
||||
}
|
||||
} else {
|
||||
throw new DeserializerException("Invalid value: " + jsonNode.getNodeType()
|
||||
+ " for expanded navigation porperty: " + navigationPropertyName,
|
||||
DeserializerException.MessageKeys.INVALID_VALUE_FOR_NAVIGATION_PROPERTY, navigationPropertyName);
|
||||
}
|
||||
entity.getNavigationLinks().add(link);
|
||||
tree.remove(navigationPropertyName);
|
||||
}
|
||||
}
|
||||
|
||||
// Check and consume all Annotations
|
||||
consumeODataEntityAnnotations(tree, entity, edmEntityType);
|
||||
|
||||
final List<String> toRemove = new ArrayList<String>();
|
||||
Iterator<Entry<String, JsonNode>> fieldsIterator = tree.fields();
|
||||
// TODO: Add custom annotation support
|
||||
while (fieldsIterator.hasNext()) {
|
||||
Map.Entry<String, JsonNode> field = (Map.Entry<String, JsonNode>) fieldsIterator.next();
|
||||
if (field.getKey().endsWith(Constants.JSON_NAVIGATION_LINK)) {
|
||||
final Link link = new LinkImpl();
|
||||
link.setTitle(getAnnotationName(field));
|
||||
link.setRel(ODataServiceVersion.V40.getNamespace(ODataServiceVersion.NamespaceKey.NAVIGATION_LINK_REL)
|
||||
+ getAnnotationName(field));
|
||||
|
||||
if (field.getValue().isValueNode()) {
|
||||
link.setHref(field.getValue().textValue());
|
||||
link.setType(ODataLinkType.ENTITY_NAVIGATION.toString());
|
||||
}
|
||||
|
||||
entity.getNavigationLinks().add(link);
|
||||
toRemove.add(field.getKey());
|
||||
} else if (field.getKey().endsWith(Constants.JSON_ASSOCIATION_LINK)) {
|
||||
final LinkImpl link = new LinkImpl();
|
||||
link.setTitle(getAnnotationName(field));
|
||||
link.setRel(ODataServiceVersion.V40.getNamespace(ODataServiceVersion.NamespaceKey.ASSOCIATION_LINK_REL)
|
||||
+ getAnnotationName(field));
|
||||
link.setHref(field.getValue().textValue());
|
||||
link.setType(ODataLinkType.ASSOCIATION.toString());
|
||||
entity.getAssociationLinks().add(link);
|
||||
|
||||
toRemove.add(field.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
// remove here to avoid iterator issues.
|
||||
tree.remove(toRemove);
|
||||
|
||||
if (tree.size() != 0) {
|
||||
throw new DeserializerException("Tree should be empty but still has content left.",
|
||||
DeserializerException.MessageKeys.TREE_NOT_EMPTY);
|
||||
}
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
private String getAnnotationName(final Map.Entry<String, JsonNode> entry) {
|
||||
return entry.getKey().substring(0, entry.getKey().indexOf('@'));
|
||||
}
|
||||
|
||||
private void consumeODataEntityAnnotations(ObjectNode tree, EntityImpl entity, EdmEntityType edmEntityType) {
|
||||
final URI contextURL;
|
||||
if (tree.hasNonNull(Constants.JSON_CONTEXT)) {
|
||||
contextURL = URI.create(tree.get(Constants.JSON_CONTEXT).textValue());
|
||||
tree.remove(Constants.JSON_CONTEXT);
|
||||
} else if (tree.hasNonNull(Constants.JSON_METADATA)) {
|
||||
contextURL = URI.create(tree.get(Constants.JSON_METADATA).textValue());
|
||||
tree.remove(Constants.JSON_METADATA);
|
||||
} else {
|
||||
contextURL = null;
|
||||
}
|
||||
if (contextURL != null) {
|
||||
entity.setBaseURI(StringUtils.substringBefore(contextURL.toASCIIString(), Constants.METADATA));
|
||||
}
|
||||
|
||||
if (tree.hasNonNull(Constants.JSON_ETAG)) {
|
||||
entity.setETag(tree.get(Constants.JSON_ETAG).textValue());
|
||||
tree.remove(Constants.JSON_ETAG);
|
||||
}
|
||||
|
||||
if (tree.hasNonNull(Constants.JSON_TYPE)) {
|
||||
entity.setType(new EdmTypeInfo.Builder().setTypeExpression(tree.get(Constants.JSON_TYPE).textValue()).build()
|
||||
.internal());
|
||||
tree.remove(Constants.JSON_TYPE);
|
||||
}
|
||||
|
||||
if (tree.hasNonNull(Constants.JSON_ID)) {
|
||||
entity.setId(URI.create(tree.get(Constants.JSON_ID).textValue()));
|
||||
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());
|
||||
entity.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());
|
||||
entity.setEditLink(link);
|
||||
|
||||
tree.remove(Constants.JSON_EDIT_LINK);
|
||||
}
|
||||
|
||||
// TODO: Should we check if this is a media resource?
|
||||
if (tree.hasNonNull(Constants.JSON_MEDIA_READ_LINK)) {
|
||||
entity.setMediaContentSource(URI.create(tree.get(Constants.JSON_MEDIA_READ_LINK).textValue()));
|
||||
tree.remove(Constants.JSON_MEDIA_READ_LINK);
|
||||
}
|
||||
if (tree.hasNonNull(Constants.JSON_MEDIA_EDIT_LINK)) {
|
||||
entity.setMediaContentSource(URI.create(tree.get(Constants.JSON_MEDIA_EDIT_LINK).textValue()));
|
||||
tree.remove(Constants.JSON_MEDIA_EDIT_LINK);
|
||||
}
|
||||
if (tree.hasNonNull(Constants.JSON_MEDIA_CONTENT_TYPE)) {
|
||||
entity.setMediaContentType(tree.get(Constants.JSON_MEDIA_CONTENT_TYPE).textValue());
|
||||
tree.remove(Constants.JSON_MEDIA_CONTENT_TYPE);
|
||||
}
|
||||
if (tree.hasNonNull(Constants.JSON_MEDIA_ETAG)) {
|
||||
entity.setMediaETag(tree.get(Constants.JSON_MEDIA_ETAG).textValue());
|
||||
tree.remove(Constants.JSON_MEDIA_ETAG);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Property consumePropertyNode(EdmProperty edmProperty, JsonNode jsonNode) throws DeserializerException {
|
||||
Property property = new PropertyImpl();
|
||||
property.setName(edmProperty.getName());
|
||||
property.setType(edmProperty.getType().getFullQualifiedName().getFullQualifiedNameAsString());
|
||||
if (edmProperty.isCollection()) {
|
||||
if (!jsonNode.isArray()) {
|
||||
throw new DeserializerException("Value for property: " + edmProperty.getName()
|
||||
+ " must be an arrat but is not.", DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY,
|
||||
edmProperty.getName());
|
||||
}
|
||||
List<Object> valueArray = new ArrayList<Object>();
|
||||
Iterator<JsonNode> iterator = jsonNode.iterator();
|
||||
switch (edmProperty.getType().getKind()) {
|
||||
case PRIMITIVE:
|
||||
while (iterator.hasNext()) {
|
||||
JsonNode arrayElement = iterator.next();
|
||||
Object value = readPrimitiveValue(edmProperty, arrayElement);
|
||||
valueArray.add(value);
|
||||
}
|
||||
property.setValue(ValueType.COLLECTION_PRIMITIVE, valueArray);
|
||||
break;
|
||||
case DEFINITION:
|
||||
while (iterator.hasNext()) {
|
||||
JsonNode arrayElement = iterator.next();
|
||||
Object value = readTypeDefinitionValue(edmProperty, arrayElement);
|
||||
valueArray.add(value);
|
||||
}
|
||||
property.setValue(ValueType.COLLECTION_PRIMITIVE, valueArray);
|
||||
case ENUM:
|
||||
while (iterator.hasNext()) {
|
||||
JsonNode arrayElement = iterator.next();
|
||||
Object value = readEnumValue(edmProperty, arrayElement);
|
||||
valueArray.add(value);
|
||||
}
|
||||
property.setValue(ValueType.COLLECTION_ENUM, valueArray);
|
||||
break;
|
||||
case COMPLEX:
|
||||
while (iterator.hasNext()) {
|
||||
JsonNode arrayElement = iterator.next();
|
||||
// read and add all complex properties
|
||||
Object value = readComplexValue(edmProperty, arrayElement);
|
||||
valueArray.add(value);
|
||||
// If navigationProperties are present we have to consume them and create a LinkedComplexValue Object
|
||||
// TODO: Complex Type Navigation Deserialization
|
||||
// read and add all annotations
|
||||
// TODO: read Complex Type Annotations
|
||||
// Afterwards the node must be empty
|
||||
if (arrayElement.size() != 0) {
|
||||
throw new DeserializerException("Tree should be empty but still has content left.",
|
||||
DeserializerException.MessageKeys.TREE_NOT_EMPTY);
|
||||
}
|
||||
}
|
||||
property.setValue(ValueType.COLLECTION_COMPLEX, valueArray);
|
||||
break;
|
||||
default:
|
||||
throw new DeserializerException("Invalid Type Kind for a property found: " + edmProperty.getType().getKind(),
|
||||
DeserializerException.MessageKeys.INVALID_TYPE_FOR_PROPERTY, edmProperty.getName());
|
||||
}
|
||||
|
||||
} else {
|
||||
switch (edmProperty.getType().getKind()) {
|
||||
case PRIMITIVE:
|
||||
Object value = readPrimitiveValue(edmProperty, jsonNode);
|
||||
property.setValue(ValueType.PRIMITIVE, value);
|
||||
break;
|
||||
case DEFINITION:
|
||||
value = readTypeDefinitionValue(edmProperty, jsonNode);
|
||||
property.setValue(ValueType.PRIMITIVE, value);
|
||||
case ENUM:
|
||||
value = readEnumValue(edmProperty, jsonNode);
|
||||
property.setValue(ValueType.PRIMITIVE, value);
|
||||
break;
|
||||
case COMPLEX:
|
||||
// read and add all complex properties
|
||||
value = readComplexValue(edmProperty, jsonNode);
|
||||
property.setValue(ValueType.COMPLEX, value);
|
||||
|
||||
// read and add all navigation properties
|
||||
// TODO: Complex Type Navigation Deserialization
|
||||
// read and add all annotations
|
||||
// TODO: read Complex Type Annotations
|
||||
// Afterwards the node must be empty
|
||||
if (jsonNode.size() != 0) {
|
||||
throw new DeserializerException("Tree should be empty but still has content left.",
|
||||
DeserializerException.MessageKeys.TREE_NOT_EMPTY);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new DeserializerException("Invalid Type Kind for a property found: " + edmProperty.getType().getKind(),
|
||||
DeserializerException.MessageKeys.INVALID_TYPE_FOR_PROPERTY, edmProperty.getName());
|
||||
}
|
||||
}
|
||||
return property;
|
||||
}
|
||||
|
||||
private Object readComplexValue(EdmProperty edmComplexProperty, JsonNode jsonNode) throws DeserializerException {
|
||||
if (jsonNode.isArray() || !jsonNode.isContainerNode()) {
|
||||
throw new DeserializerException(
|
||||
"Inavlid value for property: " + edmComplexProperty.getName() + " must not be an array or primitive value.",
|
||||
DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, edmComplexProperty.getName());
|
||||
}
|
||||
// Even if there are no properties defined we have to give back an empty list
|
||||
List<Property> propertyList = new ArrayList<Property>();
|
||||
EdmComplexType edmType = (EdmComplexType) edmComplexProperty.getType();
|
||||
// Check and consume all Properties
|
||||
for (String propertyName : edmType.getPropertyNames()) {
|
||||
EdmProperty edmProperty = (EdmProperty) edmType.getProperty(propertyName);
|
||||
JsonNode subNode = jsonNode.get(propertyName);
|
||||
if (subNode != null) {
|
||||
if (subNode.isNull() && edmProperty.isNullable() != null && edmProperty.isNullable().booleanValue() == false) {
|
||||
throw new DeserializerException("Property: " + propertyName + " must not be null.",
|
||||
DeserializerException.MessageKeys.INVALID_NULL_PROPERTY, propertyName);
|
||||
}
|
||||
Property property = consumePropertyNode(edmProperty, subNode);
|
||||
propertyList.add(property);
|
||||
((ObjectNode) jsonNode).remove(propertyName);
|
||||
}
|
||||
}
|
||||
return propertyList;
|
||||
}
|
||||
|
||||
private Object readTypeDefinitionValue(EdmProperty edmProperty, JsonNode jsonNode) throws DeserializerException {
|
||||
if (!jsonNode.isValueNode()) {
|
||||
throw new DeserializerException(
|
||||
"Inavlid value for property: " + edmProperty.getName() + " must not be an object or array.",
|
||||
DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, edmProperty.getName());
|
||||
}
|
||||
try {
|
||||
EdmTypeDefinition edmTypeDefinition = (EdmTypeDefinition) edmProperty.getType();
|
||||
Object value =
|
||||
edmTypeDefinition.valueOfString(jsonNode.asText(), edmProperty.isNullable(),
|
||||
edmTypeDefinition.getMaxLength(),
|
||||
edmTypeDefinition.getPrecision(), edmTypeDefinition.getScale(), edmTypeDefinition.isUnicode(),
|
||||
edmTypeDefinition.getDefaultType());
|
||||
return value;
|
||||
} catch (EdmPrimitiveTypeException e) {
|
||||
throw new DeserializerException(
|
||||
"Inavlid value: " + jsonNode.asText() + " for property: " + edmProperty.getName(), e,
|
||||
DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, edmProperty.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private Object readEnumValue(EdmProperty edmProperty, JsonNode jsonNode) throws DeserializerException {
|
||||
if (!jsonNode.isValueNode()) {
|
||||
throw new DeserializerException(
|
||||
"Inavlid value for property: " + edmProperty.getName() + " must not be an object or array.",
|
||||
DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, edmProperty.getName());
|
||||
}
|
||||
try {
|
||||
EdmEnumType edmEnumType = (EdmEnumType) edmProperty.getType();
|
||||
Object value =
|
||||
edmEnumType
|
||||
.valueOfString(jsonNode.asText(), edmProperty.isNullable(), edmProperty.getMaxLength(), edmProperty
|
||||
.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode(), edmEnumType.getDefaultType());
|
||||
return value;
|
||||
} catch (EdmPrimitiveTypeException e) {
|
||||
throw new DeserializerException(
|
||||
"Inavlid value: " + jsonNode.asText() + " for property: " + edmProperty.getName(), e,
|
||||
DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, edmProperty.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private Object readPrimitiveValue(EdmProperty edmProperty, JsonNode jsonNode) throws DeserializerException {
|
||||
if (!jsonNode.isValueNode()) {
|
||||
throw new DeserializerException(
|
||||
"Inavlid value for property: " + edmProperty.getName() + " must not be an object or array.",
|
||||
DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, edmProperty.getName());
|
||||
}
|
||||
try {
|
||||
EdmPrimitiveType edmPrimitiveType = (EdmPrimitiveType) edmProperty.getType();
|
||||
Object value =
|
||||
edmPrimitiveType.valueOfString(jsonNode.asText(), edmProperty.isNullable(),
|
||||
edmProperty.getMaxLength(), edmProperty.getPrecision(), edmProperty.getScale(),
|
||||
edmProperty.isUnicode(), edmPrimitiveType.getDefaultType());
|
||||
return value;
|
||||
} catch (EdmPrimitiveTypeException e) {
|
||||
throw new DeserializerException(
|
||||
"Inavlid value: " + jsonNode.asText() + " for property: " + edmProperty.getName(), e,
|
||||
DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, edmProperty.getName());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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.server.core.deserializer.json;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import org.apache.olingo.commons.api.format.ODataFormat;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.deserializer.ODataDeserializer;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ODataJsonDeserializerBasicTest {
|
||||
|
||||
@Test
|
||||
public void checkSupportedJsonFormats() throws Exception {
|
||||
ODataDeserializer deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON);
|
||||
assertNotNull(deserializer);
|
||||
deserializer = null;
|
||||
|
||||
deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON_NO_METADATA);
|
||||
assertNotNull(deserializer);
|
||||
deserializer = null;
|
||||
|
||||
deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON_FULL_METADATA);
|
||||
assertNotNull(deserializer);
|
||||
deserializer = null;
|
||||
}
|
||||
}
|
|
@ -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.server.core.deserializer.json;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.apache.olingo.commons.api.edm.Edm;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.edmx.EdmxReference;
|
||||
import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
|
||||
|
||||
public class AbstractODataDeserializerTest {
|
||||
|
||||
protected static final Edm edm = OData.newInstance().createServiceMetadata(
|
||||
new EdmTechProvider(), Collections.<EdmxReference> emptyList()).getEdm();
|
||||
|
||||
protected InputStream getFileAsStream(final String filename) throws IOException {
|
||||
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(filename);
|
||||
if (in == null) {
|
||||
throw new IOException("Requested file '" + filename + "' was not found.");
|
||||
}
|
||||
return in;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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.server.core.deserializer.json;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.apache.olingo.commons.api.data.Entity;
|
||||
import org.apache.olingo.commons.api.data.Link;
|
||||
import org.apache.olingo.commons.api.domain.ODataLinkType;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityType;
|
||||
import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
||||
import org.apache.olingo.commons.api.format.ODataFormat;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ODataDeserializerDeepInsertTest extends AbstractODataDeserializerTest {
|
||||
|
||||
@Test
|
||||
public void esAllPrimExpandedToOne() throws Exception {
|
||||
EdmEntityType edmEntityType = edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETAllPrim"));
|
||||
InputStream stream = getFileAsStream("EntityESAllPrimExpandedNavPropertyETTwoPrimOne.json");
|
||||
Entity entity = OData.newInstance().createDeserializer(ODataFormat.JSON).entity(stream, edmEntityType);
|
||||
|
||||
Link navigationLink = entity.getNavigationLink("NavPropertyETTwoPrimOne");
|
||||
assertNotNull(navigationLink);
|
||||
|
||||
assertEquals("NavPropertyETTwoPrimOne", navigationLink.getTitle());
|
||||
assertEquals(ODataLinkType.ENTITY_NAVIGATION.toString(), navigationLink.getType());
|
||||
assertNotNull(navigationLink.getInlineEntity());
|
||||
assertNull(navigationLink.getInlineEntitySet());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void esAllPrimExpandedToMany() throws Exception {
|
||||
EdmEntityType edmEntityType = edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETAllPrim"));
|
||||
InputStream stream = getFileAsStream("EntityESAllPrimExpandedNavPropertyETTwoPrimMany.json");
|
||||
Entity entity = OData.newInstance().createDeserializer(ODataFormat.JSON).entity(stream, edmEntityType);
|
||||
|
||||
Link navigationLink = entity.getNavigationLink("NavPropertyETTwoPrimMany");
|
||||
assertNotNull(navigationLink);
|
||||
|
||||
assertEquals("NavPropertyETTwoPrimMany", navigationLink.getTitle());
|
||||
assertEquals(ODataLinkType.ENTITY_SET_NAVIGATION.toString(), navigationLink.getType());
|
||||
assertNull(navigationLink.getInlineEntity());
|
||||
assertNotNull(navigationLink.getInlineEntitySet());
|
||||
assertEquals(1, navigationLink.getInlineEntitySet().getEntities().size());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* 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.server.core.deserializer.json;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.olingo.commons.api.data.Entity;
|
||||
import org.apache.olingo.commons.api.data.EntitySet;
|
||||
import org.apache.olingo.commons.api.data.Property;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityType;
|
||||
import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
||||
import org.apache.olingo.commons.api.format.ODataFormat;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ODataDeserializerEntitySetTest extends AbstractODataDeserializerTest {
|
||||
|
||||
@Test
|
||||
public void esAllPrim() throws Exception {
|
||||
EdmEntityType edmEntityType = edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETAllPrim"));
|
||||
InputStream stream = getFileAsStream("ESAllPrim.json");
|
||||
EntitySet entitySet = OData.newInstance().createDeserializer(ODataFormat.JSON).entitySet(stream, edmEntityType);
|
||||
|
||||
assertNotNull(entitySet);
|
||||
assertEquals(3, entitySet.getEntities().size());
|
||||
|
||||
//Check first entity
|
||||
Entity entity = entitySet.getEntities().get(0);
|
||||
List<Property> properties = entity.getProperties();
|
||||
assertNotNull(properties);
|
||||
assertEquals(16, properties.size());
|
||||
|
||||
assertEquals(new Short((short) 32767), entity.getProperty("PropertyInt16").getValue());
|
||||
assertEquals("First Resource - positive values", entity.getProperty("PropertyString").getValue());
|
||||
assertEquals(new Boolean(true), entity.getProperty("PropertyBoolean").getValue());
|
||||
assertEquals(new Short((short) 255), entity.getProperty("PropertyByte").getValue());
|
||||
assertEquals(new Byte((byte) 127), entity.getProperty("PropertySByte").getValue());
|
||||
assertEquals(new Integer(2147483647), entity.getProperty("PropertyInt32").getValue());
|
||||
assertEquals(new Long(9223372036854775807l), entity.getProperty("PropertyInt64").getValue());
|
||||
assertEquals(new Float(1.79E20), entity.getProperty("PropertySingle").getValue());
|
||||
assertEquals(new Double(-1.79E19), entity.getProperty("PropertyDouble").getValue());
|
||||
assertEquals(new BigDecimal(34), entity.getProperty("PropertyDecimal").getValue());
|
||||
assertNotNull(entity.getProperty("PropertyBinary").getValue());
|
||||
assertNotNull(entity.getProperty("PropertyDate").getValue());
|
||||
assertNotNull(entity.getProperty("PropertyDateTimeOffset").getValue());
|
||||
assertNotNull(entity.getProperty("PropertyDuration").getValue());
|
||||
assertNotNull(entity.getProperty("PropertyGuid").getValue());
|
||||
assertNotNull(entity.getProperty("PropertyTimeOfDay").getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void eSCompCollComp() throws Exception {
|
||||
EdmEntityType edmEntityType = edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETCompCollComp"));
|
||||
InputStream stream = getFileAsStream("ESCompCollComp.json");
|
||||
EntitySet entitySet = OData.newInstance().createDeserializer(ODataFormat.JSON).entitySet(stream, edmEntityType);
|
||||
|
||||
assertNotNull(entitySet);
|
||||
assertEquals(2, entitySet.getEntities().size());
|
||||
|
||||
//Since entity deserialization is called we do not check all entities here excplicitly
|
||||
}
|
||||
}
|
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
* 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.server.core.deserializer.json;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.olingo.commons.api.data.Entity;
|
||||
import org.apache.olingo.commons.api.data.Property;
|
||||
import org.apache.olingo.commons.api.data.ValueType;
|
||||
import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
||||
import org.apache.olingo.commons.api.format.ODataFormat;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.deserializer.ODataDeserializer;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ODataJsonDeserializerEntityTest extends AbstractODataDeserializerTest {
|
||||
|
||||
@Test
|
||||
public void simpleEntityETAllPrim() throws Exception {
|
||||
String entityString =
|
||||
"{\"PropertyInt16\":32767," +
|
||||
"\"PropertyString\":\"First Resource - positive values\"," +
|
||||
"\"PropertyBoolean\":true," +
|
||||
"\"PropertyByte\":255," +
|
||||
"\"PropertySByte\":127," +
|
||||
"\"PropertyInt32\":2147483647," +
|
||||
"\"PropertyInt64\":9223372036854775807," +
|
||||
"\"PropertySingle\":1.79E20," +
|
||||
"\"PropertyDouble\":-1.79E19," +
|
||||
"\"PropertyDecimal\":34," +
|
||||
"\"PropertyBinary\":\"ASNFZ4mrze8=\"," +
|
||||
"\"PropertyDate\":\"2012-12-03\"," +
|
||||
"\"PropertyDateTimeOffset\":\"2012-12-03T07:16:23Z\"," +
|
||||
"\"PropertyDuration\":\"PT6S\"," +
|
||||
"\"PropertyGuid\":\"01234567-89ab-cdef-0123-456789abcdef\"," +
|
||||
"\"PropertyTimeOfDay\":\"03:26:05\"}";
|
||||
InputStream stream = new ByteArrayInputStream(entityString.getBytes());
|
||||
ODataDeserializer deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON);
|
||||
Entity entity =
|
||||
deserializer.entity(stream, edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETAllPrim")));
|
||||
assertNotNull(entity);
|
||||
List<Property> properties = entity.getProperties();
|
||||
assertNotNull(properties);
|
||||
assertEquals(16, properties.size());
|
||||
|
||||
assertEquals(new Short((short) 32767), entity.getProperty("PropertyInt16").getValue());
|
||||
assertEquals("First Resource - positive values", entity.getProperty("PropertyString").getValue());
|
||||
assertEquals(new Boolean(true), entity.getProperty("PropertyBoolean").getValue());
|
||||
assertEquals(new Short((short) 255), entity.getProperty("PropertyByte").getValue());
|
||||
assertEquals(new Byte((byte) 127), entity.getProperty("PropertySByte").getValue());
|
||||
assertEquals(new Integer(2147483647), entity.getProperty("PropertyInt32").getValue());
|
||||
assertEquals(new Long(9223372036854775807l), entity.getProperty("PropertyInt64").getValue());
|
||||
assertEquals(new Float(1.79E20), entity.getProperty("PropertySingle").getValue());
|
||||
assertEquals(new Double(-1.79E19), entity.getProperty("PropertyDouble").getValue());
|
||||
assertEquals(new BigDecimal(34), entity.getProperty("PropertyDecimal").getValue());
|
||||
assertNotNull(entity.getProperty("PropertyBinary").getValue());
|
||||
assertNotNull(entity.getProperty("PropertyDate").getValue());
|
||||
assertNotNull(entity.getProperty("PropertyDateTimeOffset").getValue());
|
||||
assertNotNull(entity.getProperty("PropertyDuration").getValue());
|
||||
assertNotNull(entity.getProperty("PropertyGuid").getValue());
|
||||
assertNotNull(entity.getProperty("PropertyTimeOfDay").getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleEntityETCompAllPrim() throws Exception {
|
||||
String entityString = "{\"PropertyInt16\":32767," +
|
||||
"\"PropertyComp\":{" +
|
||||
"\"PropertyString\":\"First Resource - first\"," +
|
||||
"\"PropertyBinary\":\"ASNFZ4mrze8=\"," +
|
||||
"\"PropertyBoolean\":true," +
|
||||
"\"PropertyByte\":255," +
|
||||
"\"PropertyDate\":\"2012-10-03\"," +
|
||||
"\"PropertyDateTimeOffset\":\"2012-10-03T07:16:23.1234567Z\"," +
|
||||
"\"PropertyDecimal\":34.27," +
|
||||
"\"PropertySingle\":1.79E20," +
|
||||
"\"PropertyDouble\":-1.79E19," +
|
||||
"\"PropertyDuration\":\"PT6S\"," +
|
||||
"\"PropertyGuid\":\"01234567-89ab-cdef-0123-456789abcdef\"," +
|
||||
"\"PropertyInt16\":32767," +
|
||||
"\"PropertyInt32\":2147483647," +
|
||||
"\"PropertyInt64\":9223372036854775807," +
|
||||
"\"PropertySByte\":127," +
|
||||
"\"PropertyTimeOfDay\":\"01:00:01\"}}";
|
||||
InputStream stream = new ByteArrayInputStream(entityString.getBytes());
|
||||
ODataDeserializer deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON);
|
||||
Entity entity =
|
||||
deserializer.entity(stream, edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETCompAllPrim")));
|
||||
assertNotNull(entity);
|
||||
List<Property> properties = entity.getProperties();
|
||||
assertNotNull(properties);
|
||||
assertEquals(2, properties.size());
|
||||
|
||||
assertEquals(new Short((short) 32767), entity.getProperty("PropertyInt16").getValue());
|
||||
|
||||
assertNotNull(entity.getProperty("PropertyComp"));
|
||||
assertNotNull(entity.getProperty("PropertyComp") instanceof List);
|
||||
List<Property> complexProperties = entity.getProperty("PropertyComp").asComplex();
|
||||
assertEquals(16, complexProperties.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleEntityETCollAllPrim() throws Exception {
|
||||
final String entityString = "{"
|
||||
+ "\"PropertyInt16\":1,"
|
||||
+ "\"CollPropertyString\":"
|
||||
+ "[\"Employee1@company.example\",\"Employee2@company.example\",\"Employee3@company.example\"],"
|
||||
+ "\"CollPropertyBoolean\":[true,false,true],"
|
||||
+ "\"CollPropertyByte\":[50,200,249],"
|
||||
+ "\"CollPropertySByte\":[-120,120,126],"
|
||||
+ "\"CollPropertyInt16\":[1000,2000,30112],"
|
||||
+ "\"CollPropertyInt32\":[23232323,11223355,10000001],"
|
||||
+ "\"CollPropertyInt64\":[929292929292,333333333333,444444444444],"
|
||||
+ "\"CollPropertySingle\":[1790.0,26600.0,3210.0],"
|
||||
+ "\"CollPropertyDouble\":[-17900.0,-2.78E7,3210.0],"
|
||||
+ "\"CollPropertyDecimal\":[12,-2,1234],"
|
||||
+ "\"CollPropertyBinary\":[\"q83v\",\"ASNF\",\"VGeJ\"],"
|
||||
+ "\"CollPropertyDate\":[\"1958-12-03\",\"1999-08-05\",\"2013-06-25\"],"
|
||||
+ "\"CollPropertyDateTimeOffset\":[\"2015-08-12T03:08:34Z\",\"1970-03-28T12:11:10Z\","
|
||||
+ "\"1948-02-17T09:09:09Z\"],"
|
||||
+ "\"CollPropertyDuration\":[\"PT13S\",\"PT5H28M0S\",\"PT1H0S\"],"
|
||||
+ "\"CollPropertyGuid\":[\"ffffff67-89ab-cdef-0123-456789aaaaaa\",\"eeeeee67-89ab-cdef-0123-456789bbbbbb\","
|
||||
+ "\"cccccc67-89ab-cdef-0123-456789cccccc\"],"
|
||||
+ "\"CollPropertyTimeOfDay\":[\"04:14:13\",\"23:59:59\",\"01:12:33\"]"
|
||||
+ "}";
|
||||
InputStream stream = new ByteArrayInputStream(entityString.getBytes());
|
||||
ODataDeserializer deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON);
|
||||
Entity entity =
|
||||
deserializer.entity(stream, edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETCollAllPrim")));
|
||||
assertNotNull(entity);
|
||||
List<Property> properties = entity.getProperties();
|
||||
assertNotNull(properties);
|
||||
assertEquals(17, properties.size());
|
||||
|
||||
// All properties need 3 entires
|
||||
for (Property prop : properties) {
|
||||
if (!prop.getName().equals("PropertyInt16")) {
|
||||
assertEquals(ValueType.COLLECTION_PRIMITIVE, prop.getValueType());
|
||||
assertTrue(prop.getValue() instanceof List);
|
||||
List<? extends Object> asCollection = prop.asCollection();
|
||||
assertEquals(3, asCollection.size());
|
||||
}
|
||||
}
|
||||
Property property = entity.getProperty("CollPropertyBoolean");
|
||||
List<? extends Object> asCollection = property.asCollection();
|
||||
assertEquals(true, asCollection.get(0));
|
||||
assertEquals(false, asCollection.get(1));
|
||||
assertEquals(true, asCollection.get(2));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void simpleEntityETMixPrimCollComp() throws Exception {
|
||||
final String entityString = "{"
|
||||
+ "\"PropertyInt16\":32767,"
|
||||
+ "\"CollPropertyString\":"
|
||||
+ "[\"Employee1@company.example\",\"Employee2@company.example\",\"Employee3@company.example\"],"
|
||||
+ "\"PropertyComp\":{\"PropertyInt16\":111,\"PropertyString\":\"TEST A\"},"
|
||||
+ "\"CollPropertyComp\":["
|
||||
+ "{\"PropertyInt16\":123,\"PropertyString\":\"TEST 1\"},"
|
||||
+ "{\"PropertyInt16\":456,\"PropertyString\":\"TEST 2\"},"
|
||||
+ "{\"PropertyInt16\":789,\"PropertyString\":\"TEST 3\"}]}";
|
||||
|
||||
InputStream stream = new ByteArrayInputStream(entityString.getBytes());
|
||||
ODataDeserializer deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON);
|
||||
Entity entity =
|
||||
deserializer.entity(stream, edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETMixPrimCollComp")));
|
||||
assertNotNull(entity);
|
||||
List<Property> properties = entity.getProperties();
|
||||
assertNotNull(properties);
|
||||
assertEquals(4, properties.size());
|
||||
|
||||
Property property = entity.getProperty("CollPropertyComp");
|
||||
assertEquals(ValueType.COLLECTION_COMPLEX, property.getValueType());
|
||||
|
||||
assertTrue(property.getValue() instanceof List);
|
||||
List<? extends Object> asCollection = property.asCollection();
|
||||
assertEquals(3, asCollection.size());
|
||||
|
||||
for (Object arrayElement : asCollection) {
|
||||
assertTrue(arrayElement instanceof List);
|
||||
List<Object> castedArrayElement = (List<Object>) arrayElement;
|
||||
assertEquals(2, castedArrayElement.size());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleEntityWithContextURL() throws Exception {
|
||||
String entityString =
|
||||
"{\"@odata.context\": \"$metadata#ESAllPrim/$entity\"," +
|
||||
"\"PropertyInt16\":32767," +
|
||||
"\"PropertyString\":\"First Resource - positive values\"," +
|
||||
"\"PropertyBoolean\":true," +
|
||||
"\"PropertyByte\":255," +
|
||||
"\"PropertySByte\":127," +
|
||||
"\"PropertyInt32\":2147483647," +
|
||||
"\"PropertyInt64\":9223372036854775807," +
|
||||
"\"PropertySingle\":1.79E20," +
|
||||
"\"PropertyDouble\":-1.79E19," +
|
||||
"\"PropertyDecimal\":34," +
|
||||
"\"PropertyBinary\":\"ASNFZ4mrze8=\"," +
|
||||
"\"PropertyDate\":\"2012-12-03\"," +
|
||||
"\"PropertyDateTimeOffset\":\"2012-12-03T07:16:23Z\"," +
|
||||
"\"PropertyDuration\":\"PT6S\"," +
|
||||
"\"PropertyGuid\":\"01234567-89ab-cdef-0123-456789abcdef\"," +
|
||||
"\"PropertyTimeOfDay\":\"03:26:05\"}";
|
||||
InputStream stream = new ByteArrayInputStream(entityString.getBytes());
|
||||
ODataDeserializer deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON);
|
||||
Entity entity =
|
||||
deserializer.entity(stream, edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETAllPrim")));
|
||||
assertNotNull(entity);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
{
|
||||
"@odata.context" : "$metadata#ESAllPrim",
|
||||
"value" : [{
|
||||
"PropertyInt16" : 32767,
|
||||
"PropertyString" : "First Resource - positive values",
|
||||
"PropertyBoolean" : true,
|
||||
"PropertyByte" : 255,
|
||||
"PropertySByte" : 127,
|
||||
"PropertyInt32" : 2147483647,
|
||||
"PropertyInt64" : 9223372036854775807,
|
||||
"PropertySingle" : 1.79000000E+20,
|
||||
"PropertyDouble" : -1.7900000000000000E+19,
|
||||
"PropertyDecimal" : 34,
|
||||
"PropertyBinary" : "ASNFZ4mrze8=",
|
||||
"PropertyDate" : "2012-12-03",
|
||||
"PropertyDateTimeOffset" : "2012-12-03T07:16:23Z",
|
||||
"PropertyDuration" : "P0DT0H0M6S",
|
||||
"PropertyGuid" : "01234567-89ab-cdef-0123-456789abcdef",
|
||||
"PropertyTimeOfDay" : "03:26:05"
|
||||
}, {
|
||||
"PropertyInt16" : -32768,
|
||||
"PropertyString" : "Second Resource - negative values",
|
||||
"PropertyBoolean" : false,
|
||||
"PropertyByte" : 0,
|
||||
"PropertySByte" : -128,
|
||||
"PropertyInt32" : -2147483648,
|
||||
"PropertyInt64" : -9223372036854775808,
|
||||
"PropertySingle" : -1.79000000E+08,
|
||||
"PropertyDouble" : -1.7900000000000000E+05,
|
||||
"PropertyDecimal" : -34,
|
||||
"PropertyBinary" : "ASNFZ4mrze8=",
|
||||
"PropertyDate" : "2015-11-05",
|
||||
"PropertyDateTimeOffset" : "2005-12-03T07:17:08Z",
|
||||
"PropertyDuration" : "P0DT0H0M9S",
|
||||
"PropertyGuid" : "76543201-23ab-cdef-0123-456789dddfff",
|
||||
"PropertyTimeOfDay" : "23:49:14"
|
||||
}, {
|
||||
"PropertyInt16" : 0,
|
||||
"PropertyString" : "",
|
||||
"PropertyBoolean" : false,
|
||||
"PropertyByte" : 0,
|
||||
"PropertySByte" : 0,
|
||||
"PropertyInt32" : 0,
|
||||
"PropertyInt64" : 0,
|
||||
"PropertySingle" : 0.00000000E+00,
|
||||
"PropertyDouble" : 0.0000000000000000E+00,
|
||||
"PropertyDecimal" : 0,
|
||||
"PropertyBinary" : "",
|
||||
"PropertyDate" : "1970-01-01",
|
||||
"PropertyDateTimeOffset" : "2005-12-03T00:00:00Z",
|
||||
"PropertyDuration" : "P0DT0H0M0S",
|
||||
"PropertyGuid" : "76543201-23ab-cdef-0123-456789cccddd",
|
||||
"PropertyTimeOfDay" : "00:01:01"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"@odata.context" : "$metadata#ESCompCollComp",
|
||||
"value" : [{
|
||||
"PropertyInt16" : 32767,
|
||||
"PropertyComp" : {
|
||||
"CollPropertyComp" : [{
|
||||
"PropertyInt16" : 555,
|
||||
"PropertyString" : "1 Test Complex in Complex Property"
|
||||
}, {
|
||||
"PropertyInt16" : 666,
|
||||
"PropertyString" : "2 Test Complex in Complex property"
|
||||
}, {
|
||||
"PropertyInt16" : 777,
|
||||
"PropertyString" : "3 Test Complex in Complex property"
|
||||
}
|
||||
]
|
||||
}
|
||||
}, {
|
||||
"PropertyInt16" : 12345,
|
||||
"PropertyComp" : {
|
||||
"CollPropertyComp" : [{
|
||||
"PropertyInt16" : 888,
|
||||
"PropertyString" : "11 Test Complex in Complex property"
|
||||
}, {
|
||||
"PropertyInt16" : 999,
|
||||
"PropertyString" : "12 Test Complex in Complex property"
|
||||
}, {
|
||||
"PropertyInt16" : 0,
|
||||
"PropertyString" : "13 Test Complex in Complex property"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"@odata.context" : "$metadata#ESAllPrim/$entity",
|
||||
"PropertyInt16" : 32767,
|
||||
"PropertyString" : "First Resource - positive values",
|
||||
"PropertyBoolean" : true,
|
||||
"PropertyByte" : 255,
|
||||
"PropertySByte" : 127,
|
||||
"PropertyInt32" : 2147483647,
|
||||
"PropertyInt64" : 9223372036854775807,
|
||||
"PropertySingle" : 1.79000000E+20,
|
||||
"PropertyDouble" : -1.7900000000000000E+19,
|
||||
"PropertyDecimal" : 34,
|
||||
"PropertyBinary" : "ASNFZ4mrze8=",
|
||||
"PropertyDate" : "2012-12-03",
|
||||
"PropertyDateTimeOffset" : "2012-12-03T07:16:23Z",
|
||||
"PropertyDuration" : "P0DT0H0M6S",
|
||||
"PropertyGuid" : "01234567-89ab-cdef-0123-456789abcdef",
|
||||
"PropertyTimeOfDay" : "03:26:05",
|
||||
"NavPropertyETTwoPrimMany" : [{
|
||||
"PropertyInt16" : -365,
|
||||
"PropertyString" : "Test String2"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"@odata.context" : "$metadata#ESAllPrim/$entity",
|
||||
"PropertyInt16" : 32767,
|
||||
"PropertyString" : "First Resource - positive values",
|
||||
"PropertyBoolean" : true,
|
||||
"PropertyByte" : 255,
|
||||
"PropertySByte" : 127,
|
||||
"PropertyInt32" : 2147483647,
|
||||
"PropertyInt64" : 9223372036854775807,
|
||||
"PropertySingle" : 1.79000000E+20,
|
||||
"PropertyDouble" : -1.7900000000000000E+19,
|
||||
"PropertyDecimal" : 34,
|
||||
"PropertyBinary" : "ASNFZ4mrze8=",
|
||||
"PropertyDate" : "2012-12-03",
|
||||
"PropertyDateTimeOffset" : "2012-12-03T07:16:23Z",
|
||||
"PropertyDuration" : "P0DT0H0M6S",
|
||||
"PropertyGuid" : "01234567-89ab-cdef-0123-456789abcdef",
|
||||
"PropertyTimeOfDay" : "03:26:05",
|
||||
"NavPropertyETTwoPrimOne" : {
|
||||
"PropertyInt16" : 32767,
|
||||
"PropertyString" : "Test String4"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue