[OLINGO-534] Ignore odata.type annotation and more tests

This commit is contained in:
Christian Amend 2015-01-16 16:19:04 +01:00
parent 0aad7c037c
commit 121c7d7129
4 changed files with 256 additions and 30 deletions

View File

@ -39,7 +39,8 @@ public class DeserializerException extends ODataTranslatedException {
VALUE_ARRAY_NOT_PRESENT,
VALUE_TAG_MUST_BE_AN_ARRAY,
INVALID_ENTITY,
/** parameter: navigationPropertyName */INVALID_VALUE_FOR_NAVIGATION_PROPERTY;
/** parameter: navigationPropertyName */INVALID_VALUE_FOR_NAVIGATION_PROPERTY,
DUPLICATE_PROPERTY;
@Override
public String getKey() {

View File

@ -31,6 +31,7 @@ public interface ODataDeserializer {
/**
* Deserializes an entity stream into an {@link Entity} object.
* Validates: property types, no double properties, correct json types
* @param stream
* @param edmEntityType
* @return deserialized {@link Entity} object
@ -46,5 +47,7 @@ public interface ODataDeserializer {
* @throws DeserializerException
*/
EntitySet entityCollection(InputStream stream, EdmEntityType edmEntityType) throws DeserializerException;
}

View File

@ -31,7 +31,6 @@ 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;
@ -43,7 +42,6 @@ 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;
@ -55,6 +53,8 @@ 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.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
@ -64,13 +64,18 @@ public class ODataJsonDeserializer implements ODataDeserializer {
@Override
public EntitySet entityCollection(InputStream stream, EdmEntityType edmEntityType) throws DeserializerException {
try {
JsonParser parser = new JsonFactory(new ObjectMapper()).createParser(stream);
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);
return consumeEntitySetNode(edmEntityType, tree);
} catch (JsonParseException e) {
throw new DeserializerException("An JsonParseException occourred", e,
DeserializerException.MessageKeys.JSON_SYNTAX_EXCEPTION);
} catch (JsonMappingException e) {
throw new DeserializerException("Duplicate property detected", e,
DeserializerException.MessageKeys.DUPLICATE_PROPERTY);
} catch (IOException e) {
throw new DeserializerException("An IOException occourred", e, DeserializerException.MessageKeys.IO_EXCEPTION);
}
@ -150,7 +155,9 @@ public class ODataJsonDeserializer implements ODataDeserializer {
@Override
public Entity entity(InputStream stream, EdmEntityType edmEntityType) throws DeserializerException {
try {
JsonParser parser = new JsonFactory(new ObjectMapper()).createParser(stream);
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);
return consumeEntityNode(edmEntityType, tree);
@ -158,6 +165,9 @@ public class ODataJsonDeserializer implements ODataDeserializer {
} catch (JsonParseException e) {
throw new DeserializerException("An JsonParseException occourred", e,
DeserializerException.MessageKeys.JSON_SYNTAX_EXCEPTION);
} catch (JsonMappingException e) {
throw new DeserializerException("Duplicate property detected", e,
DeserializerException.MessageKeys.DUPLICATE_PROPERTY);
} catch (IOException e) {
throw new DeserializerException("An IOException occourred", e, DeserializerException.MessageKeys.IO_EXCEPTION);
}
@ -229,28 +239,10 @@ public class ODataJsonDeserializer implements ODataDeserializer {
// 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);
if (field.getKey().endsWith(Constants.JSON_NAVIGATION_LINK)
|| field.getKey().endsWith(Constants.JSON_ASSOCIATION_LINK) || field.getKey().endsWith(Constants.JSON_TYPE)) {
//navigation links, association links and type information have to be ignored in requests.
toRemove.add(field.getKey());
}
}
@ -266,10 +258,6 @@ public class ODataJsonDeserializer implements ODataDeserializer {
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)) {
@ -520,4 +508,14 @@ public class ODataJsonDeserializer implements ODataDeserializer {
DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, edmProperty.getName());
}
}
// @Override
// public Entity entity(InputStream stream, EdmEntityType edmEntityType)
// throws DeserializerException {
// try {
// return new JsonDeserializer(ODataServiceVersion.V40, true).toEntity(stream).getPayload();
// } catch (Exception e) {
// throw new DeserializerException("", e, DeserializerException.MessageKeys.JSON_SYNTAX_EXCEPTION);
// }
// }
}

View File

@ -33,11 +33,26 @@ 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.DeserializerException;
import org.apache.olingo.server.api.deserializer.ODataDeserializer;
import org.junit.Ignore;
import org.junit.Test;
public class ODataJsonDeserializerEntityTest extends AbstractODataDeserializerTest {
@Test
public void emptyEntity() throws Exception {
String entityString = "{}";
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(0, properties.size());
}
@Test
public void simpleEntityETAllPrim() throws Exception {
String entityString =
@ -84,6 +99,22 @@ public class ODataJsonDeserializerEntityTest extends AbstractODataDeserializerTe
assertNotNull(entity.getProperty("PropertyTimeOfDay").getValue());
}
@Test
public void simpleEntityETAllPrimNoTAllPropertiesPresent() throws Exception {
String entityString =
"{\"PropertyInt16\":32767," +
"\"PropertyString\":\"First Resource - positive values\"" +
"}";
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(2, properties.size());
}
@Test
public void simpleEntityETCompAllPrim() throws Exception {
String entityString = "{\"PropertyInt16\":32767," +
@ -233,4 +264,197 @@ public class ODataJsonDeserializerEntityTest extends AbstractODataDeserializerTe
assertNotNull(entity);
}
@Test
public void ingoreSomeAnnotations() throws Exception {
// We have to ignore @odata.navigation, @odata.association and @odata.type annotations on server side
String entityString =
"{\"PropertyInt16\":32767,"
+ "\"PropertyString@odata.type\":\"test\","
+ "\"Navigation@odata.navigationLink\":\"test\","
+ "\"Association@odata.associationLink\":\"test\","
+ "\"PropertyString\":\"First Resource - positive values\""
+ "}";
InputStream stream = new ByteArrayInputStream(entityString.getBytes());
ODataDeserializer deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON);
deserializer.entity(stream, edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETAllPrim")));
}
// ---------------------------------- Negative Tests -----------------------------------------------------------
@Test(expected = DeserializerException.class)
public void etAllPrimWithNullValue() throws Exception {
String entityString =
"{\"PropertyInt16\":32767," +
"\"PropertyString\":\"First Resource - positive values\"," +
"\"PropertyBoolean\":true," +
"\"PropertyByte\":null," +
"\"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());
try {
ODataDeserializer deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON);
deserializer.entity(stream, edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETAllPrim")));
} catch (DeserializerException e) {
assertEquals(DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, e.getMessageKey());
throw e;
}
}
@Test(expected = DeserializerException.class)
public void eTCollAllPrimWithNullValue() throws Exception {
final String entityString = "{"
+ "\"PropertyInt16\":1,"
+ "\"CollPropertyString\":"
+ "[\"Employee1@company.example\",\"Employee2@company.example\",\"Employee3@company.example\"],"
+ "\"CollPropertyBoolean\":[true,null,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());
try {
ODataDeserializer deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON);
deserializer.entity(stream, edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETCollAllPrim")));
} catch (DeserializerException e) {
assertEquals(DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, e.getMessageKey());
throw e;
}
}
@Test(expected = DeserializerException.class)
public void doublePrimitiveProperty() throws Exception {
final String entityString = "{\"@odata.context\":\"$metadata#ESTwoPrim/$entity\"," +
"\"PropertyInt16\":32766,\"PropertyInt16\":32766,\"PropertyString\":\"Test String1\"}";
InputStream stream = new ByteArrayInputStream(entityString.getBytes());
try {
ODataDeserializer deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON);
deserializer.entity(stream, edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETTwoPrim")));
} catch (DeserializerException e) {
assertEquals(DeserializerException.MessageKeys.DUPLICATE_PROPERTY, e.getMessageKey());
throw e;
}
}
@Test(expected = DeserializerException.class)
public void doubleComplexProperty() throws Exception {
final String entityString = "{"
+ "\"PropertyInt16\":32767,"
+ "\"CollPropertyString\":"
+ "[\"Employee1@company.example\",\"Employee2@company.example\",\"Employee3@company.example\"],"
+ "\"PropertyComp\":{\"PropertyInt16\":111,\"PropertyString\":\"TEST A\"},"
+ "\"PropertyComp\":{\"PropertyInt16\":111,\"PropertyString\":\"TEST B\"},"
+ "\"CollPropertyComp\":["
+ "{\"PropertyInt16\":123,\"PropertyString\":\"TEST 1\"},"
+ "{\"PropertyInt16\":456,\"PropertyString\":\"TEST 2\"},"
+ "{\"PropertyInt16\":789,\"PropertyString\":\"TEST 3\"}]}";
InputStream stream = new ByteArrayInputStream(entityString.getBytes());
try {
ODataDeserializer deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON);
deserializer.entity(stream, edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETMixPrimCollComp")));
} catch (DeserializerException e) {
assertEquals(DeserializerException.MessageKeys.DUPLICATE_PROPERTY, e.getMessageKey());
throw e;
}
}
@Test(expected = DeserializerException.class)
public void doubleComplexPropertyCollection() 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\"}],"
+ "\"CollPropertyComp\":["
+ "{\"PropertyInt16\":123,\"PropertyString\":\"TEST 1\"},"
+ "{\"PropertyInt16\":456,\"PropertyString\":\"TEST 2\"},"
+ "{\"PropertyInt16\":789,\"PropertyString\":\"TEST 3\"}]"
+ "}";
InputStream stream = new ByteArrayInputStream(entityString.getBytes());
try {
ODataDeserializer deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON);
deserializer.entity(stream, edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETMixPrimCollComp")));
} catch (DeserializerException e) {
assertEquals(DeserializerException.MessageKeys.DUPLICATE_PROPERTY, e.getMessageKey());
throw e;
}
}
@Test(expected = DeserializerException.class)
public void doublePrimitivePropertyCollection() throws Exception {
final String entityString = "{"
+ "\"PropertyInt16\":32767,"
+ "\"CollPropertyString\":"
+ "[\"Employee1@company.example\",\"Employee2@company.example\",\"Employee3@company.example\"],"
+ "\"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());
try {
ODataDeserializer deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON);
deserializer.entity(stream, edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETMixPrimCollComp")));
} catch (DeserializerException e) {
assertEquals(DeserializerException.MessageKeys.DUPLICATE_PROPERTY, e.getMessageKey());
throw e;
}
}
@Ignore
@Test(expected = DeserializerException.class)
public void customAnnotationsLeadToNotImplemented() throws Exception {
final String entityString = "{"
+ "\"PropertyInt16\":32767,"
+ "\"CollPropertyString@custom.annotation\": 12,"
+ "\"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());
try {
ODataDeserializer deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON);
deserializer.entity(stream, edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETMixPrimCollComp")));
} catch (DeserializerException e) {
assertEquals(DeserializerException.MessageKeys.NOT_IMPLEMENTED, e.getMessageKey());
throw e;
}
}
}