[OLINGO-603] Refactor action parameter deserialization part 1

This commit is contained in:
Christian Amend 2015-03-31 14:42:08 +02:00
parent d94edf568c
commit 3e8c50646e
10 changed files with 150 additions and 72 deletions

View File

@ -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();
}

View File

@ -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;

View File

@ -37,12 +37,23 @@ public abstract class AbstractValuable implements Valuable, Annotatable {
private ValueType valueType = null;
private Object value = null;
private final List<Annotation> annotations = new ArrayList<Annotation>();
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;

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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());
}
}

View File

@ -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");
}
}

View File

@ -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<Parameter> actionParameters(InputStream stream, EdmAction edmAction) throws DeserializerException;
}

View File

@ -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<Parameter> 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<Parameter> parameters = new ArrayList<Parameter>();
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<Parameter> 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 (<code>jsonNode.isValueNode()</code>) 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
*/

View File

@ -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<Property> properties = entity.getProperties();
assertNotNull(properties);
assertTrue(properties.isEmpty());
final List<Parameter> 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<Property> 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<Parameter> 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<Parameter> 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)));