[OLINGO-1064] ComplexType is deserialized as Primitive Type if the value is NULL

Signed-off-by: Christian Amend <christian.amend@sap.com>
This commit is contained in:
i050510 2017-04-25 14:05:30 +05:30 committed by Christian Amend
parent 7e262c8d07
commit 272719d59f
6 changed files with 205 additions and 27 deletions

View File

@ -29,6 +29,7 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.URI;
import java.util.Collections;
@ -37,6 +38,7 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.olingo.client.api.EdmEnabledODataClient;
import org.apache.olingo.client.api.ODataClient;
import org.apache.olingo.client.api.communication.ODataClientErrorException;
import org.apache.olingo.client.api.communication.request.cud.ODataDeleteRequest;
@ -72,7 +74,9 @@ import org.apache.olingo.client.api.domain.ClientServiceDocument;
import org.apache.olingo.client.api.domain.ClientValue;
import org.apache.olingo.client.api.edm.xml.Reference;
import org.apache.olingo.client.api.edm.xml.XMLMetadata;
import org.apache.olingo.client.api.serialization.ODataDeserializerException;
import org.apache.olingo.client.api.uri.URIBuilder;
import org.apache.olingo.client.core.ODataClientFactory;
import org.apache.olingo.client.core.uri.URIUtils;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmActionImport;
@ -108,6 +112,9 @@ public class BasicITCase extends AbstractParamTecSvcITCase {
private static final String ES_TWO_PRIM = "ESTwoPrim";
private static final String ES_KEY_NAV = "ESKeyNav";
private static final String ES_MIX_PRIM_COLL_COMP = "ESMixPrimCollComp";
private static final String PROPERTY_COMP_NAV = "CollPropertyCompNav";
private static final String COL_PROPERTY_COMP = "CollPropertyComp";
private static final String PROPERTY_COMP_TWO_PRIM = "PropertyCompTwoPrim";
@Test
public void readServiceDocument() {
@ -1464,4 +1471,107 @@ public class BasicITCase extends AbstractParamTecSvcITCase {
assertEquals(BigDecimal.valueOf(34), response.getBody().getPrimitiveValue().toValue());
}
@Test
public void test1Olingo1064() throws ODataDeserializerException {
EdmMetadataRequest request = getClient().getRetrieveRequestFactory().getMetadataRequest(SERVICE_URI);
assertNotNull(request);
setCookieHeader(request);
ODataRetrieveResponse<Edm> response = request.execute();
saveCookieHeader(response);
assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode());
Edm edm = response.getBody();
EdmEnabledODataClient odataClient = ODataClientFactory.getEdmEnabledClient(SERVICE_URI, edm, null);
final InputStream input = Thread.currentThread().getContextClassLoader().
getResourceAsStream("ESCompAllPrimWithValueForComplexProperty.json");
ClientEntity entity = odataClient.getReader().readEntity(input, ContentType.JSON);
assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode());
assertNotNull(entity.getProperty(PROPERTY_COMP).getComplexValue());
assertEquals("olingo.odata.test1.CTAllPrim", entity.getProperty(PROPERTY_COMP).getComplexValue().getTypeName());
assertEquals(PROPERTY_COMP, entity.getProperty(PROPERTY_COMP).getName());
assertNull(entity.getProperty(PROPERTY_COMP).getComplexValue().get("PropertyString").getPrimitiveValue());
assertNull(entity.getProperty(PROPERTY_COMP).getComplexValue().get("PropertyBoolean").getPrimitiveValue());
}
@Test
public void test2Olingo1064() throws ODataDeserializerException {
EdmMetadataRequest request = getClient().getRetrieveRequestFactory().getMetadataRequest(SERVICE_URI);
assertNotNull(request);
setCookieHeader(request);
ODataRetrieveResponse<Edm> response = request.execute();
saveCookieHeader(response);
assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode());
Edm edm = response.getBody();
EdmEnabledODataClient odataClient = ODataClientFactory.getEdmEnabledClient(SERVICE_URI, edm, null);
final InputStream input = Thread.currentThread().getContextClassLoader().
getResourceAsStream("ESCompAllPrimWithNullValueForComplexProperty.json");
ClientEntity entity = odataClient.getReader().readEntity(input, ContentType.JSON);
assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode());
assertNotNull(entity.getProperty(PROPERTY_COMP).getComplexValue());
assertEquals("olingo.odata.test1.CTAllPrim", entity.getProperty(PROPERTY_COMP).getComplexValue().getTypeName());
assertEquals(PROPERTY_COMP, entity.getProperty(PROPERTY_COMP).getName());
assertNull(entity.getProperty(PROPERTY_COMP).getComplexValue().get(PROPERTY_COMP).getComplexValue());
}
@Test
public void test3Olingo1064() throws ODataDeserializerException {
EdmMetadataRequest request = getClient().getRetrieveRequestFactory().getMetadataRequest(SERVICE_URI);
assertNotNull(request);
setCookieHeader(request);
ODataRetrieveResponse<Edm> response = request.execute();
saveCookieHeader(response);
assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode());
Edm edm = response.getBody();
EdmEnabledODataClient odataClient = ODataClientFactory.getEdmEnabledClient(SERVICE_URI, edm, null);
final InputStream input = Thread.currentThread().getContextClassLoader().
getResourceAsStream("ESCompAllPrimWithEmptyValueForComplexProperty.json");
ClientEntity entity = odataClient.getReader().readEntity(input, ContentType.JSON);
assertEquals("olingo.odata.test1.CTAllPrim", entity.getProperty(PROPERTY_COMP).getComplexValue().getTypeName());
assertEquals(PROPERTY_COMP, entity.getProperty(PROPERTY_COMP).getName());
assertTrue(entity.getProperty(PROPERTY_COMP).getComplexValue().asJavaMap().size() == 0);
}
@SuppressWarnings("unchecked")
@Test
public void test4Olingo1064() throws ODataDeserializerException {
EdmMetadataRequest request = getClient().getRetrieveRequestFactory().getMetadataRequest(SERVICE_URI);
assertNotNull(request);
setCookieHeader(request);
ODataRetrieveResponse<Edm> response = request.execute();
saveCookieHeader(response);
assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode());
Edm edm = response.getBody();
EdmEnabledODataClient odataClient = ODataClientFactory.getEdmEnabledClient(SERVICE_URI, edm, null);
final InputStream input = Thread.currentThread().getContextClassLoader().
getResourceAsStream("ESTwoKeyNavWithNestedComplexTypes.json");
ClientEntity entity = odataClient.getReader().readEntity(input, ContentType.JSON);
assertEquals("olingo.odata.test1.CTPrimComp", entity.getProperty(PROPERTY_COMP).getComplexValue().getTypeName());
assertEquals(PROPERTY_COMP, entity.getProperty(PROPERTY_COMP).getName());
Map<String, Object> map = entity.getProperty(PROPERTY_COMP).getComplexValue().asJavaMap();
assertEquals(map.size(), 2);
assertEquals(((Map<String, Object>)map.get(PROPERTY_COMP)).size(), 16);
assertNull(entity.getProperty(PROPERTY_COMP_NAV).getComplexValue().get(PROPERTY_COMP_NAV).getComplexValue());
assertEquals("Collection(olingo.odata.test1.CTPrimComp)", entity.getProperty(COL_PROPERTY_COMP).
getCollectionValue().getTypeName());
assertEquals(0, entity.getProperty(COL_PROPERTY_COMP).getCollectionValue().size());
assertEquals("olingo.odata.test1.CTNavFiveProp", entity.getProperty(PROPERTY_COMP_NAV).
getComplexValue().getTypeName());
assertEquals("olingo.odata.test1.CTTwoPrim", entity.getProperty(PROPERTY_COMP_TWO_PRIM).
getComplexValue().getTypeName());
assertNull(entity.getProperty(PROPERTY_COMP_TWO_PRIM).getComplexValue().
get(PROPERTY_COMP_TWO_PRIM).getComplexValue());
}
}

View File

@ -0,0 +1,7 @@
{
"@odata.context": "$metadata#ESCompAllPrim/$entity",
"@odata.metadataEtag": "W/\"2010a206-ee09-4cfb-9087-df530cdbb6ea\"",
"@odata.etag": "W/\"-32768\"",
"PropertyInt16": -32768,
"PropertyComp": {}
}

View File

@ -0,0 +1,7 @@
{
"@odata.context": "$metadata#ESCompAllPrim/$entity",
"@odata.metadataEtag": "W/\"2010a206-ee09-4cfb-9087-df530cdbb6ea\"",
"@odata.etag": "W/\"-32768\"",
"PropertyInt16": -32768,
"PropertyComp": null
}

View File

@ -0,0 +1,7 @@
{
"@odata.context": "$metadata#ESCompAllPrim/$entity",
"@odata.metadataEtag": "W/\"2010a206-ee09-4cfb-9087-df530cdbb6ea\"",
"@odata.etag": "W/\"-32768\"",
"PropertyInt16": -32768,
"PropertyComp": { "PropertyString": null, "PropertyBoolean": null }
}

View File

@ -0,0 +1,38 @@
{
"@odata.context": "../$metadata#ESTwoKeyNav",
"@odata.metadataEtag": "W/\"e5db7a43-370a-44d7-9600-9f0443e6e351\"",
"PropertyInt16": 1,
"PropertyString": "2",
"PropertyComp": {
"PropertyInt16": 11,
"PropertyComp": {
"PropertyString": "StringValue",
"PropertyBinary": "ASNFZ4mrze8=",
"PropertyBoolean": true,
"PropertyByte": 255,
"PropertyDate": "2012-12-03",
"PropertyDateTimeOffset": null,
"PropertyDecimal": 34,
"PropertySingle": 17900000,
"PropertyDouble": -17900000,
"PropertyDuration": "PT6S",
"PropertyGuid": "01234567-89ab-cdef-0123-456789abcdef",
"PropertyInt16": 32767,
"PropertyInt32": 2147483647,
"PropertyInt64": 9223372036854775807,
"PropertySByte": 127,
"PropertyTimeOfDay": "21:05:59"
}
},
"PropertyCompNav": {
"PropertyInt16": 1,
"PropertyComp": null
},
"CollPropertyComp": [],
"CollPropertyCompNav": null,
"CollPropertyString": [
"1",
"2"
],
"PropertyCompTwoPrim": null
}

View File

@ -470,7 +470,7 @@ public class ODataBinderImpl implements ODataBinder {
URIUtils.getURI(base, href), title, metadataETag));
}
}
for (ClientLink link : odataLinked.getNavigationLinks()) {
if (!(link instanceof ClientInlineEntity) && !(link instanceof ClientInlineEntitySet)) {
odataAnnotations(linked.getNavigationLink(link.getName()), link);
@ -858,10 +858,10 @@ public class ODataBinderImpl implements ODataBinder {
}
lcValue.add(getODataProperty(edmPropertyType, property));
}
odataNavigationLinks(edmType, valuable.asComplex(), lcValue, metadataETag, contextURL);
odataAnnotations(valuable.asComplex(), lcValue);
value = lcValue;
} else {
if (valuable.isGeospatial()) {
@ -874,31 +874,40 @@ public class ODataBinderImpl implements ODataBinder {
: EdmPrimitiveTypeKind.valueOfFQN(type.toString())).
build();
} else if (valuable.isPrimitive() || valuable.getValueType() == null) {
// fixes non-string values treated as string when no type information is available at de-serialization level
if (type != null && !EdmPrimitiveTypeKind.String.getFullQualifiedName().equals(type)
&& EdmPrimitiveType.EDM_NAMESPACE.equals(type.getNamespace())
&& valuable.asPrimitive() instanceof String) {
final EdmPrimitiveType primitiveType =
EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.valueOf(type.getName()));
final Class<?> returnType = primitiveType.getDefaultType().isAssignableFrom(Calendar.class)
? Timestamp.class : primitiveType.getDefaultType();
try {
valuable.setValue(valuable.getValueType(),
primitiveType.valueOfString(valuable.asPrimitive().toString(),
null, null, Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null,
returnType));
} catch (EdmPrimitiveTypeException e) {
throw new IllegalArgumentException(e);
}
// fixes non-string values treated as string when no type information is available at de-serialization level
Edm edm = null;
if (client instanceof EdmEnabledODataClient && type != null) {
edm = ((EdmEnabledODataClient) client).getEdm(metadataETag);
}
value = client.getObjectFactory().newPrimitiveValueBuilder().
setValue(valuable.asPrimitive()).
setType(type == null || !EdmPrimitiveType.EDM_NAMESPACE.equals(type.getNamespace())
? null
: EdmPrimitiveTypeKind.valueOfFQN(type.toString())).
build();
if (edm != null && edm.getComplexType(type) != null) {
ClientComplexValue cValue = client.getObjectFactory().newComplexValue(type.toString());
cValue.add(new ClientPropertyImpl(((Property)valuable).getName(), null));
value = cValue;
} else {
if (type != null && !EdmPrimitiveTypeKind.String.getFullQualifiedName().equals(type)
&& EdmPrimitiveType.EDM_NAMESPACE.equals(type.getNamespace())
&& valuable.asPrimitive() instanceof String) {
final EdmPrimitiveType primitiveType =
EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.valueOf(type.getName()));
final Class<?> returnType = primitiveType.getDefaultType().isAssignableFrom(Calendar.class)
? Timestamp.class : primitiveType.getDefaultType();
try {
valuable.setValue(valuable.getValueType(),
primitiveType.valueOfString(valuable.asPrimitive().toString(),
null, null, Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null,
returnType));
} catch (EdmPrimitiveTypeException e) {
throw new IllegalArgumentException(e);
}
}
value = client.getObjectFactory().newPrimitiveValueBuilder().
setValue(valuable.asPrimitive()).
setType(type == null || !EdmPrimitiveType.EDM_NAMESPACE.equals(type.getNamespace())
? null
: EdmPrimitiveTypeKind.valueOfFQN(type.toString())).
build();
}
} else if (valuable.isComplex()) {
final ClientComplexValue cValue =
client.getObjectFactory().newComplexValue(type == null ? null : type.toString());