From bc0129490be7ba29ec7f6ba5dbd77b91d6778086 Mon Sep 17 00:00:00 2001 From: Ramesh Reddy Date: Tue, 7 Oct 2014 09:52:46 -0500 Subject: [PATCH] [OLINGO-444] - Adding the ablity to add key predicates to Context URL - Fixed the wrong ContextURL with readProperty in TechnicalProcessor class - Added unit tests for ContextURL, and integration tests for PropertyProcessor's readProperty & readPropertyValue methods Signed-off-by: Michael Bolz --- .../olingo/fit/tecsvc/client/BasicITCase.java | 107 ++++++++++++++++++ .../olingo/commons/api/data/ContextURL.java | 53 ++++++++- .../serializer/utils/ContextURLBuilder.java | 12 +- .../utils/ContextURLBuilderTest.java | 81 +++++++++++++ .../server/tecsvc/data/DataProvider.java | 2 +- .../tecsvc/processor/TechnicalProcessor.java | 53 +++++++-- .../json/ODataJsonSerializerTest.java | 4 +- 7 files changed, 295 insertions(+), 17 deletions(-) diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java index f7097a32d..46a6b9650 100644 --- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java @@ -36,6 +36,7 @@ import org.apache.olingo.client.api.communication.ODataClientErrorException; import org.apache.olingo.client.api.communication.request.retrieve.EdmMetadataRequest; import org.apache.olingo.client.api.communication.request.retrieve.ODataEntityRequest; import org.apache.olingo.client.api.communication.request.retrieve.ODataEntitySetRequest; +import org.apache.olingo.client.api.communication.request.retrieve.ODataPropertyRequest; import org.apache.olingo.client.api.communication.request.retrieve.ODataServiceDocumentRequest; import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse; import org.apache.olingo.client.api.v4.ODataClient; @@ -177,6 +178,112 @@ public class BasicITCase extends AbstractBaseTestITCase { + "}"; assertEquals(expectedResult, IOUtils.toString(response.getRawResponse(), "UTF-8")); } + + @Test + public void readSimpleProperty() throws Exception { + ODataPropertyRequest request = getClient().getRetrieveRequestFactory() + .getPropertyRequest(getClient().newURIBuilder(SERVICE_URI) + .appendEntitySetSegment("ESTwoPrim") + .appendKeySegment(32766) + .appendPropertySegment("PropertyString") + .build()); + + assertNotNull(request); + + ODataRetrieveResponse response = request.execute(); + assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode()); + assertThat(response.getContentType(), containsString(ContentType.APPLICATION_JSON.toContentTypeString())); + + final ODataProperty property = response.getBody(); + assertNotNull(property); + assertNotNull(property.getPrimitiveValue()); + assertEquals("Test String1", property.getPrimitiveValue().toValue()); + } + + @Test + public void readSimplePropertyContextURL() throws Exception { + ODataPropertyRequest request = getClient().getRetrieveRequestFactory() + .getPropertyRequest(getClient().newURIBuilder(SERVICE_URI) + .appendEntitySetSegment("ESTwoPrim") + .appendKeySegment(32766) + .appendPropertySegment("PropertyString") + .build()); + ODataRetrieveResponse response = request.execute(); + String expectedResult = + "{\"@odata.context\":\"$metadata#ESTwoPrim(32766)/PropertyString\"," + + "\"value\":\"Test String1\"}"; + assertEquals(expectedResult, IOUtils.toString(response.getRawResponse(), "UTF-8")); + } + + @Test + public void readComplexProperty() throws Exception { + ODataPropertyRequest request = getClient().getRetrieveRequestFactory() + .getPropertyRequest(getClient().newURIBuilder(SERVICE_URI) + .appendEntitySetSegment("ESMixPrimCollComp") + .appendKeySegment(7) + .appendPropertySegment("PropertyComp") + .build()); + ODataRetrieveResponse response = request.execute(); + assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode()); + assertThat(response.getContentType(), containsString(ContentType.APPLICATION_JSON.toContentTypeString())); + + final ODataProperty property = response.getBody(); + assertNotNull(property); + assertNotNull(property.getComplexValue()); + assertEquals("TEST B", property.getComplexValue().get("PropertyString").getPrimitiveValue().toValue()); + } + + @Test + public void readComplexPropertyContextURL() throws Exception { + ODataPropertyRequest request = getClient().getRetrieveRequestFactory() + .getPropertyRequest(getClient().newURIBuilder(SERVICE_URI) + .appendEntitySetSegment("ESMixPrimCollComp") + .appendKeySegment(7) + .appendPropertySegment("PropertyComp") + .build()); + ODataRetrieveResponse response = request.execute(); + String expectedResult = + "{\"@odata.context\":\"$metadata#ESMixPrimCollComp(7)/PropertyComp\"," + + "\"PropertyInt16\":222,\"PropertyString\":\"TEST B\"}"; + assertEquals(expectedResult, IOUtils.toString(response.getRawResponse(), "UTF-8")); + } + + @Test(expected=ODataClientErrorException.class) + public void readUnknownProperty() throws Exception { + ODataPropertyRequest request = getClient().getRetrieveRequestFactory() + .getPropertyRequest(getClient().newURIBuilder(SERVICE_URI) + .appendEntitySetSegment("ESTwoPrim") + .appendKeySegment(32766) + .appendPropertySegment("Unknown") + .build()); + ODataRetrieveResponse response = request.execute(); + assertEquals(HttpStatusCode.NOT_FOUND.getStatusCode(), response.getStatusCode()); + } + + @Test + public void readNoContentProperty() throws Exception { + ODataPropertyRequest request = getClient().getRetrieveRequestFactory() + .getPropertyRequest(getClient().newURIBuilder(SERVICE_URI) + .appendEntitySetSegment("ESTwoPrim") + .appendKeySegment(-32766) + .appendPropertySegment("PropertyString") + .build()); + ODataRetrieveResponse response = request.execute(); + assertEquals(HttpStatusCode.NO_CONTENT.getStatusCode(), response.getStatusCode()); + } + + @Test + public void readPropertyValue() throws Exception { + ODataPropertyRequest request = getClient().getRetrieveRequestFactory() + .getPropertyRequest(getClient().newURIBuilder(SERVICE_URI) + .appendEntitySetSegment("ESTwoPrim") + .appendKeySegment(32766) + .appendPropertySegment("PropertyString") + .appendValueSegment() + .build()); + ODataRetrieveResponse response = request.execute(); + assertEquals("Test String1", IOUtils.toString(response.getRawResponse(), "UTF-8")); + } @Override protected CommonODataClient getClient() { diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ContextURL.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ContextURL.java index 7b750de91..476da1035 100644 --- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ContextURL.java +++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ContextURL.java @@ -19,9 +19,11 @@ package org.apache.olingo.commons.api.data; import java.net.URI; +import java.util.Map; import org.apache.olingo.commons.api.edm.EdmEntitySet; import org.apache.olingo.commons.api.edm.EdmEntityType; +import org.apache.olingo.commons.api.edm.EdmType; /** * High-level representation of a context URL, built from the string value returned by a service; provides access to the @@ -35,11 +37,17 @@ public class ContextURL { private String entitySetOrSingletonOrType; + private boolean isCollection = false; + private String derivedEntity; private String selectList; private String navOrPropertyPath; + + private String keyPath; + + private Suffix suffix; public enum Suffix { @@ -57,7 +65,6 @@ public class ContextURL { } } - private Suffix suffix; private ContextURL() { } @@ -70,6 +77,10 @@ public class ContextURL { return entitySetOrSingletonOrType; } + public boolean isCollection() { + return isCollection; + } + public String getDerivedEntity() { return derivedEntity; } @@ -81,6 +92,10 @@ public class ContextURL { public String getNavOrPropertyPath() { return navOrPropertyPath; } + + public String getKeyPath() { + return keyPath; + } public Suffix getSuffix() { return suffix; @@ -127,11 +142,47 @@ public class ContextURL { contextURL.entitySetOrSingletonOrType = entitySet.getName(); return this; } + + public Builder keySegment(Object value) { + if (value != null) { + contextURL.keyPath = String.valueOf(value); + } + return this; + } + + public Builder keySegment(Map values) { + if (values != null && !values.isEmpty()) { + + if (values.size() == 1) { + return keySegment(values.values().iterator().next()); + } + + StringBuilder sb = new StringBuilder(); + for (String key:values.keySet()) { + if (sb.length() > 0) { + sb.append(","); + } + sb.append(key).append("=").append(values.get(key)); + } + contextURL.keyPath = sb.toString(); + } + return this; + } public Builder entitySetOrSingletonOrType(final String entitySetOrSingletonOrType) { contextURL.entitySetOrSingletonOrType = entitySetOrSingletonOrType; return this; } + + public Builder propertyType(final EdmType type) { + contextURL.entitySetOrSingletonOrType = type.getFullQualifiedName().toString(); + return this; + } + + public Builder asCollection() { + contextURL.isCollection = true; + return this; + } public Builder derived(final EdmEntityType derivedType) { contextURL.derivedEntity = derivedType.getFullQualifiedName().getFullQualifiedNameAsString(); diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilder.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilder.java index 86b29c620..9bfac40dd 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilder.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilder.java @@ -38,7 +38,14 @@ public final class ContextURLBuilder { } result.append(Constants.METADATA); if (contextURL.getEntitySetOrSingletonOrType() != null) { - result.append('#').append(Encoder.encode(contextURL.getEntitySetOrSingletonOrType())); + result.append('#'); + if(contextURL.isCollection()) { + result.append("Collection(") + .append(Encoder.encode(contextURL.getEntitySetOrSingletonOrType())) + .append(")"); + } else { + result.append(Encoder.encode(contextURL.getEntitySetOrSingletonOrType())); + } } if (contextURL.getDerivedEntity() != null) { if (contextURL.getEntitySetOrSingletonOrType() == null) { @@ -46,6 +53,9 @@ public final class ContextURLBuilder { } result.append('/').append(Encoder.encode(contextURL.getDerivedEntity())); } + if (contextURL.getKeyPath() != null) { + result.append('(').append(contextURL.getKeyPath()).append(')'); + } if (contextURL.getSelectList() != null) { result.append('(').append(contextURL.getSelectList()).append(')'); } diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilderTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilderTest.java index bc136f402..a8b5e717d 100644 --- a/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilderTest.java +++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilderTest.java @@ -19,13 +19,28 @@ package org.apache.olingo.server.core.serializer.utils; import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.TreeMap; + import org.apache.olingo.commons.api.data.ContextURL; import org.apache.olingo.commons.api.data.ContextURL.Suffix; +import org.apache.olingo.commons.api.edm.EdmComplexType; import org.apache.olingo.commons.api.edm.EdmEntitySet; import org.apache.olingo.commons.api.edm.EdmEntityType; +import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; import org.apache.olingo.commons.api.edm.FullQualifiedName; +import org.apache.olingo.commons.core.edm.primitivetype.EdmString; +import org.apache.olingo.server.api.edm.provider.ComplexType; +import org.apache.olingo.server.api.edm.provider.EdmProvider; +import org.apache.olingo.server.api.edm.provider.NavigationProperty; +import org.apache.olingo.server.api.edm.provider.Property; +import org.apache.olingo.server.core.edm.provider.EdmComplexTypeImpl; +import org.apache.olingo.server.core.edm.provider.EdmProviderImpl; import org.junit.Test; import org.mockito.Mockito; @@ -89,6 +104,72 @@ public class ContextURLBuilderTest { assertEquals("http://host/service/$metadata#Customers/Model.VipCustomer/$entity", ContextURLBuilder.create(contextURL).toASCIIString()); } + + @Test + public void buildPropertyValue() { + EdmEntitySet entitySet = Mockito.mock(EdmEntitySet.class); + Mockito.when(entitySet.getName()).thenReturn("Customers"); + ContextURL contextURL = ContextURL.with().serviceRoot(URI.create("http://host/service/")) + .entitySet(entitySet) + .keySegment(1) + .navOrPropertyPath("Name") + .build(); + assertEquals("http://host/service/$metadata#Customers(1)/Name", + ContextURLBuilder.create(contextURL).toASCIIString()); + TreeMap keys = new TreeMap(); + keys.put("one", 1); + keys.put("two", "'two'"); + contextURL = ContextURL.with().serviceRoot(URI.create("http://host/service/")) + .entitySet(entitySet) + .keySegment(keys) + .navOrPropertyPath("Name") + .build(); + assertEquals("http://host/service/$metadata#Customers(one=1,two='two')/Name", + ContextURLBuilder.create(contextURL).toASCIIString()); + } + + @Test + public void buildPrimitiveType() { + EdmEntitySet entitySet = Mockito.mock(EdmEntitySet.class); + Mockito.when(entitySet.getName()).thenReturn("Customers"); + ContextURL contextURL = ContextURL.with().serviceRoot(URI.create("http://host/service/")) + .propertyType(EdmString.getInstance()) + .build(); + assertEquals("http://host/service/$metadata#Edm.String", + ContextURLBuilder.create(contextURL).toASCIIString()); + + contextURL = ContextURL.with().serviceRoot(URI.create("http://host/service/")) + .propertyType(EdmString.getInstance()).asCollection() + .build(); + assertEquals("http://host/service/$metadata#Collection(Edm.String)", + ContextURLBuilder.create(contextURL).toString()); + } + + @Test + public void buildComplexType() throws Exception { + EdmProvider provider = mock(EdmProvider.class); + EdmProviderImpl edm = new EdmProviderImpl(provider); + + FullQualifiedName baseName = new FullQualifiedName("namespace", "BaseTypeName"); + ComplexType baseComplexType = new ComplexType(); + List baseProperties = new ArrayList(); + baseProperties.add(new Property().setName("prop1").setType(EdmPrimitiveTypeKind.String.getFullQualifiedName())); + List baseNavigationProperties = new ArrayList(); + baseNavigationProperties.add(new NavigationProperty().setName("nav1")); + baseComplexType.setName("BaseTypeName").setAbstract(false).setOpenType(false).setProperties(baseProperties) + .setNavigationProperties(baseNavigationProperties); + when(provider.getComplexType(baseName)).thenReturn(baseComplexType); + + EdmComplexType baseType = EdmComplexTypeImpl.getInstance(edm, baseName, baseComplexType); + + EdmEntitySet entitySet = Mockito.mock(EdmEntitySet.class); + Mockito.when(entitySet.getName()).thenReturn("Customers"); + ContextURL contextURL = ContextURL.with().serviceRoot(URI.create("http://host/service/")) + .propertyType(baseType) + .build(); + assertEquals("http://host/service/$metadata#namespace.BaseTypeName", + ContextURLBuilder.create(contextURL).toASCIIString()); + } @Test(expected = IllegalArgumentException.class) public void buildSuffixWithoutEntitySet() { diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java index f4120dba1..e8deff3b2 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java @@ -131,7 +131,7 @@ public class DataProvider { entitySet.getEntities().add(new EntityImpl() .addProperty(createPrimitive("PropertyInt16", -32766)) - .addProperty(createPrimitive("PropertyString", "Test String3"))); + .addProperty(createPrimitive("PropertyString", null))); entitySet.getEntities().add(new EntityImpl() .addProperty(createPrimitive("PropertyInt16", Short.MAX_VALUE)) diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java index 17ae20144..63a59c36c 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java @@ -18,13 +18,21 @@ */ package org.apache.olingo.server.tecsvc.processor; +import java.io.ByteArrayInputStream; +import java.io.UnsupportedEncodingException; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.TreeMap; + import org.apache.olingo.commons.api.data.ContextURL; +import org.apache.olingo.commons.api.data.ContextURL.Suffix; import org.apache.olingo.commons.api.data.Entity; import org.apache.olingo.commons.api.data.EntitySet; -import org.apache.olingo.commons.api.data.ContextURL.Suffix; import org.apache.olingo.commons.api.data.Property; import org.apache.olingo.commons.api.edm.Edm; import org.apache.olingo.commons.api.edm.EdmEntitySet; +import org.apache.olingo.commons.api.edm.EdmEntityType; import org.apache.olingo.commons.api.edm.EdmPrimitiveType; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException; import org.apache.olingo.commons.api.edm.EdmProperty; @@ -37,14 +45,15 @@ import org.apache.olingo.server.api.OData; import org.apache.olingo.server.api.ODataApplicationException; import org.apache.olingo.server.api.ODataRequest; import org.apache.olingo.server.api.ODataResponse; -import org.apache.olingo.server.api.processor.EntitySetProcessor; import org.apache.olingo.server.api.processor.EntityProcessor; +import org.apache.olingo.server.api.processor.EntitySetProcessor; import org.apache.olingo.server.api.processor.PropertyProcessor; import org.apache.olingo.server.api.serializer.ODataSerializer; import org.apache.olingo.server.api.serializer.ODataSerializerOptions; import org.apache.olingo.server.api.serializer.SerializerException; import org.apache.olingo.server.api.uri.UriInfo; import org.apache.olingo.server.api.uri.UriInfoResource; +import org.apache.olingo.server.api.uri.UriParameter; import org.apache.olingo.server.api.uri.UriResource; import org.apache.olingo.server.api.uri.UriResourceEntitySet; import org.apache.olingo.server.api.uri.UriResourceKind; @@ -53,11 +62,6 @@ import org.apache.olingo.server.api.uri.queryoption.ExpandOption; import org.apache.olingo.server.api.uri.queryoption.SelectOption; import org.apache.olingo.server.tecsvc.data.DataProvider; -import java.io.ByteArrayInputStream; -import java.io.UnsupportedEncodingException; -import java.util.List; -import java.util.Locale; - /** * Technical Processor which provides currently implemented processor functionality. */ @@ -212,14 +216,38 @@ public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor, .navOrPropertyPath(propertyPath) .build(); } - + + private Map getKeys(EdmEntityType entityType, + List parameters) throws ODataApplicationException { + TreeMap keys = new TreeMap(); + for (UriParameter param: parameters) { + final EdmProperty property = (EdmProperty) entityType.getProperty(param.getName()); + final EdmPrimitiveType type = (EdmPrimitiveType) property.getType(); + try { + Object keyValue = type.valueOfString(param.getText(), + property.isNullable(), property.getMaxLength(), property.getPrecision(), property.getScale(), + property.isUnicode(), type.getDefaultType()); + if (keyValue instanceof String) { + keyValue = "'"+keyValue+"'"; + } + keys.put(param.getName(), keyValue); + } catch (EdmPrimitiveTypeException e) { + throw new ODataApplicationException("Invalid key found", HttpStatusCode.BAD_REQUEST.getStatusCode(), + Locale.ROOT, e); + } + } + return keys; + } + @Override public void readProperty(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, final ContentType contentType) throws ODataApplicationException, SerializerException { validateOptions(uriInfo.asUriInfoResource()); final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo.asUriInfoResource()); + final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) uriInfo.getUriResourceParts().get(0); final Entity entity = readEntityInternal(uriInfo.asUriInfoResource(), edmEntitySet); + if (entity == null) { throw new ODataApplicationException("Nothing found.", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT); } else { @@ -236,10 +264,11 @@ public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor, final ODataFormat format = ODataFormat.fromContentType(contentType); ODataSerializer serializer = odata.createSerializer(format); response.setContent(serializer.entityProperty(edmProperty, property, - ODataSerializerOptions.with() - .contextURL(format == ODataFormat.JSON_NO_METADATA ? null : - getContextUrl(serializer, edmEntitySet, true, null, null, edmProperty.getName())) - .build())); + ODataSerializerOptions.with().contextURL(format == ODataFormat.JSON_NO_METADATA ? null : + ContextURL.with().entitySet(edmEntitySet) + .keySegment(getKeys(edmEntitySet.getEntityType(), resourceEntitySet.getKeyPredicates())) + .navOrPropertyPath(edmProperty.getName()) + .build()).build())); response.setStatusCode(HttpStatusCode.OK.getStatusCode()); response.setHeader(HttpHeader.CONTENT_TYPE, contentType.toContentTypeString()); } diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java index 7835b7a54..36e3887af 100644 --- a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java +++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java @@ -302,7 +302,7 @@ public class ODataJsonSerializerTest { final String expectedResult = "{\"value\":[" + "{\"PropertyInt16\":32766,\"PropertyString\":\"Test String1\"}," + "{\"PropertyInt16\":-365,\"PropertyString\":\"Test String2\"}," - + "{\"PropertyInt16\":-32766,\"PropertyString\":\"Test String3\"}," + + "{\"PropertyInt16\":-32766,\"PropertyString\":null}," + "{\"PropertyInt16\":32767,\"PropertyString\":\"Test String4\"}]}"; Assert.assertEquals(expectedResult, resultString); } @@ -566,7 +566,7 @@ public class ODataJsonSerializerTest { + "{\"PropertyInt32\":0,\"NavPropertyETTwoPrimOne\":null," + "\"NavPropertyETTwoPrimMany\":[" + "{\"PropertyInt16\":32766,\"PropertyString\":\"Test String1\"}," - + "{\"PropertyInt16\":-32766,\"PropertyString\":\"Test String3\"}," + + "{\"PropertyInt16\":-32766,\"PropertyString\":null}," + "{\"PropertyInt16\":32767,\"PropertyString\":\"Test String4\"}]}]}", resultString); }