[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; package org.apache.olingo.commons.api.data;
public enum ValueType { public enum ValueType {
PRIMITIVE, GEOSPATIAL, ENUM, COMPLEX, PRIMITIVE, GEOSPATIAL, ENUM, COMPLEX, ENTITY,
COLLECTION_PRIMITIVE(PRIMITIVE), COLLECTION_PRIMITIVE(PRIMITIVE),
COLLECTION_GEOSPATIAL(GEOSPATIAL), COLLECTION_GEOSPATIAL(GEOSPATIAL),
COLLECTION_ENUM(ENUM), COLLECTION_ENUM(ENUM),
COLLECTION_COMPLEX(COMPLEX); COLLECTION_COMPLEX(COMPLEX),
COLLECTION_ENTITY(ENTITY);
private final ValueType baseType; private final ValueType baseType;

View File

@ -37,12 +37,23 @@ public abstract class AbstractValuable implements Valuable, Annotatable {
private ValueType valueType = null; private ValueType valueType = null;
private Object value = null; private Object value = null;
private final List<Annotation> annotations = new ArrayList<Annotation>(); private final List<Annotation> annotations = new ArrayList<Annotation>();
private String type;
@Override @Override
public boolean isNull() { public boolean isNull() {
return value == null; return value == null;
} }
@Override
public String getType() {
return type;
}
@Override
public void setType(final String type) {
this.type = type;
}
@Override @Override
public boolean isPrimitive() { public boolean isPrimitive() {
return valueType == ValueType.PRIMITIVE; 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 { public class AnnotationImpl extends AbstractValuable implements Annotation {
private String term; private String term;
private String type;
@Override @Override
public String getTerm() { public String getTerm() {
@ -34,14 +33,4 @@ public class AnnotationImpl extends AbstractValuable implements Annotation {
public void setTerm(final String term) { public void setTerm(final String term) {
this.term = 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 { public class PropertyImpl extends AbstractValuable implements Property {
private String name; private String name;
private String type;
public PropertyImpl() {} public PropertyImpl() {}
public PropertyImpl(final String type, final String name) { public PropertyImpl(final String type, final String name) {
this.name = name; this.name = name;
this.type = type; super.setType(type);
} }
public PropertyImpl(String type, String name, ValueType valueType, Object value) { public PropertyImpl(String type, String name, ValueType valueType, Object value) {
@ -48,18 +47,8 @@ public class PropertyImpl extends AbstractValuable implements Property {
this.name = name; this.name = name;
} }
@Override
public String getType() {
return type;
}
@Override
public void setType(final String type) {
this.type = type;
}
@Override @Override
public boolean isNull() { 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.commons.lang3.StringUtils;
import org.apache.olingo.commons.api.Constants; 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.Annotation;
import org.apache.olingo.commons.api.data.ComplexValue; import org.apache.olingo.commons.api.data.ComplexValue;
import org.apache.olingo.commons.api.data.ContextURL; import org.apache.olingo.commons.api.data.ContextURL;
@ -113,6 +114,9 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
property(writer, property, false); property(writer, property, false);
} }
break; 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; package org.apache.olingo.server.api.deserializer;
import java.io.InputStream; import java.io.InputStream;
import java.util.List;
import org.apache.olingo.commons.api.data.Entity; import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.EntitySet; 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.EdmAction;
import org.apache.olingo.commons.api.edm.EdmEntityType; import org.apache.olingo.commons.api.edm.EdmEntityType;
@ -54,8 +56,8 @@ public interface ODataDeserializer {
* Validates: parameter types, no double parameters, correct json types. * Validates: parameter types, no double parameters, correct json types.
* @param stream * @param stream
* @param edmAction * @param edmAction
* @return deserialized {@link Entity} object * @return deserialized list of {@link Parameter} objects
* @throws DeserializerException * @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.Entity;
import org.apache.olingo.commons.api.data.EntitySet; import org.apache.olingo.commons.api.data.EntitySet;
import org.apache.olingo.commons.api.data.Link; 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.Property;
import org.apache.olingo.commons.api.data.ValueType; import org.apache.olingo.commons.api.data.ValueType;
import org.apache.olingo.commons.api.domain.ODataLinkType; 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.EntityImpl;
import org.apache.olingo.commons.core.data.EntitySetImpl; import org.apache.olingo.commons.core.data.EntitySetImpl;
import org.apache.olingo.commons.core.data.LinkImpl; 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.commons.core.data.PropertyImpl;
import org.apache.olingo.server.api.deserializer.DeserializerException; import org.apache.olingo.server.api.deserializer.DeserializerException;
import org.apache.olingo.server.api.deserializer.ODataDeserializer; 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.JsonFactory;
import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
@ -72,10 +75,7 @@ public class ODataJsonDeserializer implements ODataDeserializer {
@Override @Override
public EntitySet entityCollection(InputStream stream, EdmEntityType edmEntityType) throws DeserializerException { public EntitySet entityCollection(InputStream stream, EdmEntityType edmEntityType) throws DeserializerException {
try { try {
ObjectMapper objectMapper = new ObjectMapper(); final ObjectNode tree = parseJsonTree(stream);
objectMapper.configure(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY, true);
JsonParser parser = new JsonFactory(objectMapper).createParser(stream);
final ObjectNode tree = parser.getCodec().readTree(parser);
return consumeEntitySetNode(edmEntityType, tree); return consumeEntitySetNode(edmEntityType, tree);
} catch (JsonParseException e) { } catch (JsonParseException e) {
@ -145,10 +145,7 @@ public class ODataJsonDeserializer implements ODataDeserializer {
@Override @Override
public Entity entity(InputStream stream, EdmEntityType edmEntityType) throws DeserializerException { public Entity entity(InputStream stream, EdmEntityType edmEntityType) throws DeserializerException {
try { try {
ObjectMapper objectMapper = new ObjectMapper(); final ObjectNode tree = parseJsonTree(stream);
objectMapper.configure(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY, true);
JsonParser parser = new JsonFactory(objectMapper).createParser(stream);
final ObjectNode tree = parser.getCodec().readTree(parser);
return consumeEntityNode(edmEntityType, tree); return consumeEntityNode(edmEntityType, tree);
@ -183,16 +180,13 @@ public class ODataJsonDeserializer implements ODataDeserializer {
} }
@Override @Override
public Entity actionParameters(InputStream stream, final EdmAction edmAction) throws DeserializerException { public List<Parameter> actionParameters(InputStream stream, final EdmAction edmAction) throws DeserializerException {
try { try {
ObjectMapper objectMapper = new ObjectMapper(); ObjectNode tree = parseJsonTree(stream);
objectMapper.configure(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY, true); ArrayList<Parameter> parameters = new ArrayList<Parameter>();
JsonParser parser = new JsonFactory(objectMapper).createParser(stream); consumeParameters(edmAction, tree, parameters);
ObjectNode tree = parser.getCodec().readTree(parser);
EntityImpl entity = new EntityImpl();
consumeParameters(edmAction, tree, entity);
assertJsonNodeIsEmpty(tree); assertJsonNodeIsEmpty(tree);
return entity; return parameters;
} catch (final JsonParseException e) { } catch (final JsonParseException e) {
throw new DeserializerException("An JsonParseException occurred", 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 { throws DeserializerException {
for (final String name : edmAction.getParameterNames()) { 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); JsonNode jsonNode = node.get(name);
if (jsonNode == null) { if (jsonNode == null) {
if (!parameter.isNullable()) { if (!edmParameter.isNullable()) {
// TODO: new message key. // TODO: new message key.
throw new DeserializerException("Non-nullable parameter not present or null", throw new DeserializerException("Non-nullable parameter not present or null",
DeserializerException.MessageKeys.INVALID_NULL_PROPERTY, name); DeserializerException.MessageKeys.INVALID_NULL_PROPERTY, name);
} }
} else { } else {
entity.addProperty(consumePropertyNode(parameter.getName(), parameter.getType(), parameter.isCollection(), Property consumePropertyNode =
parameter.isNullable(), parameter.getMaxLength(), parameter.getPrecision(), parameter.getScale(), consumePropertyNode(edmParameter.getName(), edmParameter.getType(), edmParameter.isCollection(),
true, parameter.getMapping(), edmParameter.isNullable(), edmParameter.getMaxLength(), edmParameter.getPrecision(), edmParameter
jsonNode)); .getScale(),
true, edmParameter.getMapping(),
jsonNode);
parameter.setValue(consumePropertyNode.getValueType(), consumePropertyNode.getValue());
parameters.add(parameter);
node.remove(name); node.remove(name);
} }
} }
@ -623,7 +631,7 @@ public class ODataJsonDeserializer implements ODataDeserializer {
/** /**
* Check if JsonNode is a value node (<code>jsonNode.isValueNode()</code>) and if not throw * Check if JsonNode is a value node (<code>jsonNode.isValueNode()</code>) and if not throw
* an DeserializerException. * an DeserializerException.
* @param name name of property which is checked * @param name name of property which is checked
* @param jsonNode node which is checked * @param jsonNode node which is checked
* @throws DeserializerException is thrown if json node is not a value node * @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.math.BigDecimal;
import java.util.List; import java.util.List;
import org.apache.olingo.commons.api.data.Entity; import org.apache.olingo.commons.api.data.Parameter;
import org.apache.olingo.commons.api.data.Property;
import org.apache.olingo.commons.api.edm.FullQualifiedName; import org.apache.olingo.commons.api.edm.FullQualifiedName;
import org.apache.olingo.commons.api.format.ODataFormat; import org.apache.olingo.commons.api.format.ODataFormat;
import org.apache.olingo.server.api.OData; import org.apache.olingo.server.api.OData;
@ -39,27 +38,23 @@ public class ODataJsonDeserializerActionParametersTest extends AbstractODataDese
@Test @Test
public void empty() throws Exception { public void empty() throws Exception {
final String input = "{}"; final String input = "{}";
final Entity entity = deserialize(input, "UART"); final List<Parameter> parameters = deserialize(input, "UART");
assertNotNull(entity); assertNotNull(parameters);
final List<Property> properties = entity.getProperties(); assertTrue(parameters.isEmpty());
assertNotNull(properties);
assertTrue(properties.isEmpty());
} }
@Test @Test
public void primitive() throws Exception { public void primitive() throws Exception {
final String input = "{\"ParameterDuration\":\"P42DT11H22M33S\",\"ParameterInt16\":42}"; final String input = "{\"ParameterDuration\":\"P42DT11H22M33S\",\"ParameterInt16\":42}";
final Entity entity = deserialize(input, "UARTTwoParam"); final List<Parameter> parameters = deserialize(input, "UARTTwoParam");
assertNotNull(entity); assertNotNull(parameters);
final List<Property> properties = entity.getProperties(); assertEquals(2, parameters.size());
assertNotNull(properties); Parameter parameter = parameters.get(0);
assertEquals(2, properties.size()); assertNotNull(parameter);
Property property = properties.get(0); assertEquals((short) 42, parameter.getValue());
assertNotNull(property); parameter = parameters.get(1);
assertEquals((short) 42, property.getValue()); assertNotNull(parameter);
property = properties.get(1); assertEquals(BigDecimal.valueOf(3669753), parameter.getValue());
assertNotNull(property);
assertEquals(BigDecimal.valueOf(3669753), property.getValue());
} }
@Test(expected = DeserializerException.class) @Test(expected = DeserializerException.class)
@ -77,7 +72,7 @@ public class ODataJsonDeserializerActionParametersTest extends AbstractODataDese
deserialize("{\"ParameterInt16\":\"42\"}", "UARTParam"); 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) return OData.newInstance().createDeserializer(ODataFormat.JSON)
.actionParameters(new ByteArrayInputStream(input.getBytes()), .actionParameters(new ByteArrayInputStream(input.getBytes()),
edm.getUnboundAction(new FullQualifiedName("Namespace1_Alias", actionName))); edm.getUnboundAction(new FullQualifiedName("Namespace1_Alias", actionName)));