diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Parameter.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Parameter.java new file mode 100644 index 000000000..87058ec5f --- /dev/null +++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Parameter.java @@ -0,0 +1,32 @@ +/* + * 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.api.data; + +public interface Parameter extends Valuable { + + /** + * @return name of the parameter + */ + String getName(); + + boolean isEntity(); + + Entity asEntity(); + +} diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ValueType.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ValueType.java index 7b6d9427d..6dc460f21 100644 --- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ValueType.java +++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ValueType.java @@ -19,11 +19,12 @@ package org.apache.olingo.commons.api.data; public enum ValueType { - PRIMITIVE, GEOSPATIAL, ENUM, COMPLEX, + PRIMITIVE, GEOSPATIAL, ENUM, COMPLEX, ENTITY, COLLECTION_PRIMITIVE(PRIMITIVE), COLLECTION_GEOSPATIAL(GEOSPATIAL), COLLECTION_ENUM(ENUM), - COLLECTION_COMPLEX(COMPLEX); + COLLECTION_COMPLEX(COMPLEX), + COLLECTION_ENTITY(ENTITY); private final ValueType baseType; diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractValuable.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractValuable.java index 15a7a03fd..6a5a96f5e 100644 --- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractValuable.java +++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractValuable.java @@ -37,12 +37,23 @@ public abstract class AbstractValuable implements Valuable, Annotatable { private ValueType valueType = null; private Object value = null; private final List annotations = new ArrayList(); + private String type; @Override public boolean isNull() { return value == null; } + @Override + public String getType() { + return type; + } + + @Override + public void setType(final String type) { + this.type = type; + } + @Override public boolean isPrimitive() { return valueType == ValueType.PRIMITIVE; diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AnnotationImpl.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AnnotationImpl.java index 6a53ef35c..4e9953b47 100644 --- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AnnotationImpl.java +++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AnnotationImpl.java @@ -23,7 +23,6 @@ import org.apache.olingo.commons.api.data.Annotation; public class AnnotationImpl extends AbstractValuable implements Annotation { private String term; - private String type; @Override public String getTerm() { @@ -34,14 +33,4 @@ public class AnnotationImpl extends AbstractValuable implements Annotation { public void setTerm(final String term) { this.term = term; } - - @Override - public String getType() { - return type; - } - - @Override - public void setType(final String type) { - this.type = type; - } } diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/ParameterImpl.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/ParameterImpl.java new file mode 100644 index 000000000..fc2a1a98a --- /dev/null +++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/ParameterImpl.java @@ -0,0 +1,47 @@ +/* + * 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.Entity; +import org.apache.olingo.commons.api.data.Parameter; +import org.apache.olingo.commons.api.data.ValueType; + +public class ParameterImpl extends AbstractValuable implements Parameter { + + String name; + + @Override + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public boolean isEntity() { + return getValueType() == ValueType.ENTITY; + } + + @Override + public Entity asEntity() { + return isEntity() ? (Entity) getValue() : null; + } +} diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/PropertyImpl.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/PropertyImpl.java index 31583e320..7b31da73e 100755 --- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/PropertyImpl.java +++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/PropertyImpl.java @@ -24,13 +24,12 @@ import org.apache.olingo.commons.api.data.ValueType; public class PropertyImpl extends AbstractValuable implements Property { private String name; - private String type; public PropertyImpl() {} public PropertyImpl(final String type, final String name) { this.name = name; - this.type = type; + super.setType(type); } public PropertyImpl(String type, String name, ValueType valueType, Object value) { @@ -48,18 +47,8 @@ public class PropertyImpl extends AbstractValuable implements Property { this.name = name; } - @Override - public String getType() { - return type; - } - - @Override - public void setType(final String type) { - this.type = type; - } - @Override public boolean isNull() { - return getValue() == null || "Edm.Null".equals(type); + return getValue() == null || "Edm.Null".equals(getType()); } } diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/AtomSerializer.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/AtomSerializer.java index b6d9a7490..6bd5fbb95 100644 --- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/AtomSerializer.java +++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/AtomSerializer.java @@ -30,6 +30,7 @@ import javax.xml.stream.XMLStreamWriter; import org.apache.commons.lang3.StringUtils; import org.apache.olingo.commons.api.Constants; +import org.apache.olingo.commons.api.ODataRuntimeException; import org.apache.olingo.commons.api.data.Annotation; import org.apache.olingo.commons.api.data.ComplexValue; import org.apache.olingo.commons.api.data.ContextURL; @@ -113,6 +114,9 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize property(writer, property, false); } break; + case ENTITY: + case COLLECTION_ENTITY: + throw new ODataRuntimeException("Entities cannot appear in this payload"); } } diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/deserializer/ODataDeserializer.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/deserializer/ODataDeserializer.java index d5f7343aa..b361844a7 100644 --- a/lib/server-api/src/main/java/org/apache/olingo/server/api/deserializer/ODataDeserializer.java +++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/deserializer/ODataDeserializer.java @@ -19,9 +19,11 @@ package org.apache.olingo.server.api.deserializer; import java.io.InputStream; +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.Parameter; import org.apache.olingo.commons.api.edm.EdmAction; import org.apache.olingo.commons.api.edm.EdmEntityType; @@ -54,8 +56,8 @@ public interface ODataDeserializer { * Validates: parameter types, no double parameters, correct json types. * @param stream * @param edmAction - * @return deserialized {@link Entity} object + * @return deserialized list of {@link Parameter} objects * @throws DeserializerException */ - Entity actionParameters(InputStream stream, EdmAction edmAction) throws DeserializerException; + List actionParameters(InputStream stream, EdmAction edmAction) throws DeserializerException; } diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializer.java index ed3454cee..74c73c8f1 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializer.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializer.java @@ -31,6 +31,7 @@ import org.apache.olingo.commons.api.data.ComplexValue; 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.Parameter; import org.apache.olingo.commons.api.data.Property; import org.apache.olingo.commons.api.data.ValueType; import org.apache.olingo.commons.api.domain.ODataLinkType; @@ -51,6 +52,7 @@ import org.apache.olingo.commons.core.data.ComplexValueImpl; 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.ParameterImpl; import org.apache.olingo.commons.core.data.PropertyImpl; import org.apache.olingo.server.api.deserializer.DeserializerException; import org.apache.olingo.server.api.deserializer.ODataDeserializer; @@ -58,6 +60,7 @@ 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.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonNode; @@ -72,10 +75,7 @@ public class ODataJsonDeserializer implements ODataDeserializer { @Override public EntitySet entityCollection(InputStream stream, EdmEntityType edmEntityType) throws DeserializerException { try { - ObjectMapper objectMapper = new ObjectMapper(); - objectMapper.configure(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY, true); - JsonParser parser = new JsonFactory(objectMapper).createParser(stream); - final ObjectNode tree = parser.getCodec().readTree(parser); + final ObjectNode tree = parseJsonTree(stream); return consumeEntitySetNode(edmEntityType, tree); } catch (JsonParseException e) { @@ -145,10 +145,7 @@ public class ODataJsonDeserializer implements ODataDeserializer { @Override public Entity entity(InputStream stream, EdmEntityType edmEntityType) throws DeserializerException { try { - ObjectMapper objectMapper = new ObjectMapper(); - objectMapper.configure(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY, true); - JsonParser parser = new JsonFactory(objectMapper).createParser(stream); - final ObjectNode tree = parser.getCodec().readTree(parser); + final ObjectNode tree = parseJsonTree(stream); return consumeEntityNode(edmEntityType, tree); @@ -183,16 +180,13 @@ public class ODataJsonDeserializer implements ODataDeserializer { } @Override - public Entity actionParameters(InputStream stream, final EdmAction edmAction) throws DeserializerException { + public List actionParameters(InputStream stream, final EdmAction edmAction) throws DeserializerException { try { - ObjectMapper objectMapper = new ObjectMapper(); - objectMapper.configure(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY, true); - JsonParser parser = new JsonFactory(objectMapper).createParser(stream); - ObjectNode tree = parser.getCodec().readTree(parser); - EntityImpl entity = new EntityImpl(); - consumeParameters(edmAction, tree, entity); + ObjectNode tree = parseJsonTree(stream); + ArrayList parameters = new ArrayList(); + consumeParameters(edmAction, tree, parameters); assertJsonNodeIsEmpty(tree); - return entity; + return parameters; } catch (final JsonParseException e) { throw new DeserializerException("An JsonParseException occurred", e, @@ -206,22 +200,36 @@ public class ODataJsonDeserializer implements ODataDeserializer { } } - private void consumeParameters(final EdmAction edmAction, ObjectNode node, EntityImpl entity) + private ObjectNode parseJsonTree(InputStream stream) throws IOException, JsonParseException, JsonProcessingException { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.configure(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY, true); + JsonParser parser = new JsonFactory(objectMapper).createParser(stream); + ObjectNode tree = parser.getCodec().readTree(parser); + return tree; + } + + private void consumeParameters(final EdmAction edmAction, ObjectNode node, ArrayList parameters) throws DeserializerException { for (final String name : edmAction.getParameterNames()) { - final EdmParameter parameter = edmAction.getParameter(name); + final EdmParameter edmParameter = edmAction.getParameter(name); + ParameterImpl parameter = new ParameterImpl(); + parameter.setName(name); JsonNode jsonNode = node.get(name); if (jsonNode == null) { - if (!parameter.isNullable()) { + if (!edmParameter.isNullable()) { // TODO: new message key. throw new DeserializerException("Non-nullable parameter not present or null", DeserializerException.MessageKeys.INVALID_NULL_PROPERTY, name); } } else { - entity.addProperty(consumePropertyNode(parameter.getName(), parameter.getType(), parameter.isCollection(), - parameter.isNullable(), parameter.getMaxLength(), parameter.getPrecision(), parameter.getScale(), - true, parameter.getMapping(), - jsonNode)); + Property consumePropertyNode = + consumePropertyNode(edmParameter.getName(), edmParameter.getType(), edmParameter.isCollection(), + edmParameter.isNullable(), edmParameter.getMaxLength(), edmParameter.getPrecision(), edmParameter + .getScale(), + true, edmParameter.getMapping(), + jsonNode); + parameter.setValue(consumePropertyNode.getValueType(), consumePropertyNode.getValue()); + parameters.add(parameter); node.remove(name); } } @@ -302,7 +310,7 @@ public class ODataJsonDeserializer implements ODataDeserializer { EntitySetImpl inlineEntitySet = new EntitySetImpl(); inlineEntitySet.getEntities().addAll(consumeEntitySetArray(edmNavigationProperty.getType(), jsonNode)); link.setInlineEntitySet(inlineEntitySet); - } else if (!jsonNode.isArray() && (!jsonNode.isValueNode() || jsonNode.isNull()) + } else if (!jsonNode.isArray() && (!jsonNode.isValueNode() || jsonNode.isNull()) && !edmNavigationProperty.isCollection()) { link.setType(ODataLinkType.ENTITY_NAVIGATION.toString()); if (!jsonNode.isNull()) { @@ -623,7 +631,7 @@ public class ODataJsonDeserializer implements ODataDeserializer { /** * Check if JsonNode is a value node (jsonNode.isValueNode()) and if not throw * an DeserializerException. - * @param name name of property which is checked + * @param name name of property which is checked * @param jsonNode node which is checked * @throws DeserializerException is thrown if json node is not a value node */ diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerActionParametersTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerActionParametersTest.java index 2e6a18191..80668eb10 100644 --- a/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerActionParametersTest.java +++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerActionParametersTest.java @@ -26,8 +26,7 @@ import java.io.ByteArrayInputStream; 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.Parameter; import org.apache.olingo.commons.api.edm.FullQualifiedName; import org.apache.olingo.commons.api.format.ODataFormat; import org.apache.olingo.server.api.OData; @@ -39,27 +38,23 @@ public class ODataJsonDeserializerActionParametersTest extends AbstractODataDese @Test public void empty() throws Exception { final String input = "{}"; - final Entity entity = deserialize(input, "UART"); - assertNotNull(entity); - final List properties = entity.getProperties(); - assertNotNull(properties); - assertTrue(properties.isEmpty()); + final List parameters = deserialize(input, "UART"); + assertNotNull(parameters); + assertTrue(parameters.isEmpty()); } @Test public void primitive() throws Exception { final String input = "{\"ParameterDuration\":\"P42DT11H22M33S\",\"ParameterInt16\":42}"; - final Entity entity = deserialize(input, "UARTTwoParam"); - assertNotNull(entity); - final List properties = entity.getProperties(); - assertNotNull(properties); - assertEquals(2, properties.size()); - Property property = properties.get(0); - assertNotNull(property); - assertEquals((short) 42, property.getValue()); - property = properties.get(1); - assertNotNull(property); - assertEquals(BigDecimal.valueOf(3669753), property.getValue()); + final List parameters = deserialize(input, "UARTTwoParam"); + assertNotNull(parameters); + assertEquals(2, parameters.size()); + Parameter parameter = parameters.get(0); + assertNotNull(parameter); + assertEquals((short) 42, parameter.getValue()); + parameter = parameters.get(1); + assertNotNull(parameter); + assertEquals(BigDecimal.valueOf(3669753), parameter.getValue()); } @Test(expected = DeserializerException.class) @@ -77,7 +72,7 @@ public class ODataJsonDeserializerActionParametersTest extends AbstractODataDese deserialize("{\"ParameterInt16\":\"42\"}", "UARTParam"); } - private Entity deserialize(final String input, final String actionName) throws DeserializerException { + private List deserialize(final String input, final String actionName) throws DeserializerException { return OData.newInstance().createDeserializer(ODataFormat.JSON) .actionParameters(new ByteArrayInputStream(input.getBytes()), edm.getUnboundAction(new FullQualifiedName("Namespace1_Alias", actionName)));