[OLINGO-659] more clean-up, small fixes, and additional tests Signed-off-by: Christian Amend <[email protected]>
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/2a841552 Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/2a841552 Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/2a841552 Branch: refs/heads/olingo712 Commit: 2a841552f4935c57e7a21be0c25cb042a9863e8f Parents: 94b3917 Author: Klaus Straubinger <[email protected]> Authored: Thu Jun 25 16:11:50 2015 +0200 Committer: Christian Amend <[email protected]> Committed: Thu Jun 25 16:26:38 2015 +0200 ---------------------------------------------------------------------- .../olingo/commons/api/format/AcceptType.java | 7 +- .../olingo/commons/api/format/ContentType.java | 74 +++---- .../olingo/commons/api/http/HttpHeader.java | 4 + .../commons/api/format/ContentTypeTest.java | 16 +- .../olingo/server/core/ContentNegotiator.java | 32 ++- .../core/batchhandler/BatchPartHandler.java | 1 - .../core/deserializer/batch/BatchBodyPart.java | 9 +- .../deserializer/batch/BatchParserCommon.java | 34 ++- .../batch/BatchRequestTransformator.java | 2 +- .../json/ODataJsonDeserializer.java | 40 ++-- .../serializer/json/ODataJsonSerializer.java | 214 +++++++++---------- .../json/ServiceDocumentJsonSerializer.java | 33 ++- .../server/core/ContentNegotiatorTest.java | 3 +- .../json/ODataJsonDeserializerBasicTest.java | 82 +++---- .../tecsvc/processor/TechnicalProcessor.java | 7 +- .../json/ODataJsonDeserializerEntityTest.java | 26 +-- .../json/ODataJsonSerializerTest.java | 156 ++++++++++---- .../serializer/json/ServiceDocumentTest.java | 11 + 18 files changed, 397 insertions(+), 354 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2a841552/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/AcceptType.java ---------------------------------------------------------------------- diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/AcceptType.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/AcceptType.java index 874944b..ec273be 100644 --- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/AcceptType.java +++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/AcceptType.java @@ -22,6 +22,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.TreeMap; @@ -158,7 +159,11 @@ public class AcceptType { } public Map<String, String> getParameters() { - return parameters; + return Collections.unmodifiableMap(parameters); + } + + public String getParameter(final String name) { + return parameters.get(name.toLowerCase(Locale.ROOT)); } public Float getQuality() { http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2a841552/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/ContentType.java ---------------------------------------------------------------------- diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/ContentType.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/ContentType.java index 57f73df..473ff58 100644 --- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/ContentType.java +++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/ContentType.java @@ -24,6 +24,7 @@ import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; @@ -60,16 +61,16 @@ public final class ContentType { public static final ContentType APPLICATION_JSON = new ContentType(APPLICATION, "json", null); public static final ContentType JSON = ContentType.create(ContentType.APPLICATION_JSON, - PARAMETER_ODATA_METADATA + '=' + VALUE_ODATA_METADATA_MINIMAL); + PARAMETER_ODATA_METADATA, VALUE_ODATA_METADATA_MINIMAL); public static final ContentType JSON_NO_METADATA = ContentType.create(ContentType.APPLICATION_JSON, - PARAMETER_ODATA_METADATA + '=' + VALUE_ODATA_METADATA_NONE); + PARAMETER_ODATA_METADATA, VALUE_ODATA_METADATA_NONE); public static final ContentType JSON_FULL_METADATA = ContentType.create(ContentType.APPLICATION_JSON, - PARAMETER_ODATA_METADATA + '=' + VALUE_ODATA_METADATA_FULL); + PARAMETER_ODATA_METADATA, VALUE_ODATA_METADATA_FULL); public static final ContentType APPLICATION_XML = new ContentType(APPLICATION, "xml", null); public static final ContentType APPLICATION_ATOM_XML = new ContentType(APPLICATION, "atom+xml", null); - public static final ContentType APPLICATION_ATOM_XML_ENTRY = create(APPLICATION_ATOM_XML, "type=entry"); - public static final ContentType APPLICATION_ATOM_XML_FEED = create(APPLICATION_ATOM_XML, "type=feed"); + public static final ContentType APPLICATION_ATOM_XML_ENTRY = create(APPLICATION_ATOM_XML, "type", "entry"); + public static final ContentType APPLICATION_ATOM_XML_FEED = create(APPLICATION_ATOM_XML, "type", "feed"); public static final ContentType APPLICATION_ATOM_SVC = new ContentType(APPLICATION, "atomsvc+xml", null); public static final ContentType APPLICATION_OCTET_STREAM = new ContentType(APPLICATION, "octet-stream", null); @@ -142,38 +143,23 @@ public final class ContentType { } /** - * Creates a content type from format and key-value pairs for parameters. - * - * @param contentType for example "application/json" - * @param parameters for example "a=b", "c=d" - * @return a new <code>ContentType</code> object + * Creates a content type from an existing content type and an additional parameter as key-value pair. + * @param contentType an existing content type + * @param parameterName the name of the additional parameter + * @param parameterValue the value of the additional parameter + * @return a new {@link ContentType} object */ - public static ContentType create(final String contentType, final String... parameters) { - ContentType ct = parse(contentType); - - for (String p : parameters) { - final String[] keyvalue = TypeUtil.parseParameter(p); - ct.parameters.put(keyvalue[0], keyvalue[1]); + public static ContentType create(final ContentType contentType, + final String parameterName, final String parameterValue) { + if (parameterName == null || parameterName.isEmpty() || parameterName.indexOf(TypeUtil.WHITESPACE_CHAR) >= 0) { + throw new IllegalArgumentException("Illegal parameter name '" + parameterName + "'."); } - - return ct; - } - - /** - * Creates a content type from an existing content type and additional key-value pairs for parameters. - * - * @param contentType for example "application/json" - * @param parameters for example "a=b", "c=d" - * @return a new <code>ContentType</code> object - */ - public static ContentType create(final ContentType contentType, final String... parameters) { - ContentType ct = new ContentType(contentType.type, contentType.subtype, contentType.parameters); - - for (String p : parameters) { - final String[] keyvalue = TypeUtil.parseParameter(p); - ct.parameters.put(keyvalue[0], keyvalue[1]); + if (Character.isWhitespace(parameterValue.charAt(0))) { + throw new IllegalArgumentException("Value of parameter '" + parameterName + "' starts with whitespace."); } + ContentType ct = new ContentType(contentType.type, contentType.subtype, contentType.parameters); + ct.parameters.put(parameterName.toLowerCase(Locale.ROOT), parameterValue); return ct; } @@ -240,17 +226,19 @@ public final class ContentType { TypeUtil.parseParameters(params, parameters); } + /** Gets the type of this content type. */ public String getType() { return type; } + /** Gets the subtype of this content type. */ public String getSubtype() { return subtype; } /** - * - * @return parameters of this {@link ContentType} as unmodifiable map. + * Gets the parameters of this content type. + * @return parameters of this {@link ContentType} as unmodifiable map */ public Map<String, String> getParameters() { return Collections.unmodifiableMap(parameters); @@ -258,13 +246,13 @@ public final class ContentType { /** * Returns the value of a given parameter. - * If the parameter does not exists the method returns null + * If the parameter does not exists the method returns null. * - * @param name The parameter to get - * @return the value of the parameter or null if the parameter is not present + * @param name the name of the parameter to get (case-insensitive) + * @return the value of the parameter or <code>null</code> if the parameter is not present */ public String getParameter(final String name) { - return parameters.get(name); + return parameters.get(name.toLowerCase(Locale.ROOT)); } @Override @@ -300,17 +288,15 @@ public final class ContentType { while (entries.hasNext()) { final Entry<String, String> e = entries.next(); final Entry<String, String> oe = otherEntries.next(); - if (!areEqual(e.getKey(), oe.getKey())) { - return false; - } - if (!areEqual(e.getValue(), oe.getValue())) { + if (!areEqual(e.getKey(), oe.getKey()) + || !areEqual(e.getValue(), oe.getValue())) { return false; } } + return true; } else { return false; } - return true; } /** http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2a841552/lib/commons-api/src/main/java/org/apache/olingo/commons/api/http/HttpHeader.java ---------------------------------------------------------------------- diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/http/HttpHeader.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/http/HttpHeader.java index f7b9364..1036b88 100644 --- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/http/HttpHeader.java +++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/http/HttpHeader.java @@ -135,10 +135,14 @@ public interface HttpHeader { * OData Version 4.0 Part 1: Protocol</a> and <a href="https://www.ietf.org/rfc/rfc7240.txt">RFC 7240</a>. */ public static final String PREFERENCE_APPLIED = "Preference-Applied"; + /** See <a href="http://www.rfc-editor.org/rfc/rfc7233.txt">RFC 7233</a>. */ + public static final String RANGE = "Range"; /** * See {@link <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.37">HTTP/1.1 documentation</a>}. */ public static final String RETRY_AFTER = "Retry-After"; + /** See <a href="http://www.rfc-editor.org/rfc/rfc7230.txt">RFC 7230</a>. */ + public static final String TE = "TE"; /** * See {@link <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.43">HTTP/1.1 documentation</a>}. */ http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2a841552/lib/commons-api/src/test/java/org/apache/olingo/commons/api/format/ContentTypeTest.java ---------------------------------------------------------------------- diff --git a/lib/commons-api/src/test/java/org/apache/olingo/commons/api/format/ContentTypeTest.java b/lib/commons-api/src/test/java/org/apache/olingo/commons/api/format/ContentTypeTest.java index 8a7c642..6f7460b 100644 --- a/lib/commons-api/src/test/java/org/apache/olingo/commons/api/format/ContentTypeTest.java +++ b/lib/commons-api/src/test/java/org/apache/olingo/commons/api/format/ContentTypeTest.java @@ -78,21 +78,23 @@ public class ContentTypeTest { @Test public void testCreateWithParameter() { - assertEquals(ContentType.create("a/b;c=d"), ContentType.create("a/b", "c=d")); - assertEquals(ContentType.create("a/b;e=f;c=d"), ContentType.create("a/b", "c=d", "e=f")); - assertEquals(ContentType.create("a/b;e=f;c=d"), ContentType.create("A/B", "C=D", "E=F")); + assertEquals(ContentType.create("a/b;c=d"), ContentType.create(ContentType.create("a/b"), "c", "d")); + assertEquals(ContentType.create("a/b;e=f;c=d"), ContentType.create( + ContentType.create(ContentType.create("a/b"), "c", "d"), "e", "f")); + assertEquals(ContentType.create("a/b;e=f;c=d"), ContentType.create( + ContentType.create(ContentType.create("A/B"), "C", "D"), "E", "F")); } @Test public void testCreateAndModify() { ContentType ct1 = ContentType.create("a/b"); - assertEquals(ContentType.create("a/b;c=d"), ContentType.create(ct1, "c=d")); + assertEquals(ContentType.create("a/b;c=d"), ContentType.create(ct1, "c", "d")); ContentType ct2 = ContentType.create("a/b;c=d"); - assertEquals(ContentType.create("a/b;c=d;e=f"), ContentType.create(ct2, "e=f")); - assertEquals(ContentType.create("a/b;c=g"), ContentType.create(ct2, "c=g")); + assertEquals(ContentType.create("a/b;c=d;e=f"), ContentType.create(ct2, "e", "f")); + assertEquals(ContentType.create("a/b;c=g"), ContentType.create(ct2, "c", "g")); - assertFalse(ContentType.create(ct2, "c=g").equals(ct2)); + assertFalse(ContentType.create(ct2, "c", "g").equals(ct2)); } @Test http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2a841552/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java index a262b69..f35c277 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java @@ -83,8 +83,8 @@ public class ContentNegotiator { final String formatString = formatOption.getFormat().trim(); final ContentType contentType = JSON.equalsIgnoreCase(formatString) ? ContentType.JSON : - XML.equalsIgnoreCase(formatString) ? ContentType.APPLICATION_XML : - ATOM.equalsIgnoreCase(formatString) ? ContentType.APPLICATION_ATOM_XML : null; + XML.equalsIgnoreCase(formatString) ? ContentType.APPLICATION_XML : + ATOM.equalsIgnoreCase(formatString) ? ContentType.APPLICATION_ATOM_XML : null; try { result = getAcceptedType( AcceptType.fromContentType(contentType == null ? @@ -128,26 +128,24 @@ public class ContentNegotiator { for (final AcceptType acceptedType : acceptedContentTypes) { for (final ContentType supportedContentType : supportedContentTypes) { ContentType contentType = supportedContentType; - if (acceptedType.getParameters().containsKey("charset")) { - final String value = acceptedType.getParameters().get("charset"); - if ("utf8".equalsIgnoreCase(value) || "utf-8".equalsIgnoreCase(value)) { - contentType = ContentType.create(contentType, ContentType.PARAMETER_CHARSET + "=utf-8"); + final String charSetValue = acceptedType.getParameter(ContentType.PARAMETER_CHARSET); + if (charSetValue != null) { + if ("utf8".equalsIgnoreCase(charSetValue) || "utf-8".equalsIgnoreCase(charSetValue)) { + contentType = ContentType.create(contentType, ContentType.PARAMETER_CHARSET, "utf-8"); } else { throw new IllegalArgumentException("charset not supported: " + acceptedType); } } - - if(acceptedType.getParameters().containsKey("ieee754compatible")) { - final String value = acceptedType.getParameters().get("ieee754compatible"); - if("true".equalsIgnoreCase(value)) { - contentType = ContentType.create(contentType, ContentType.PARAMETER_IEEE754_COMPATIBLE + "=true"); - } else if("false".equalsIgnoreCase(value)) { - contentType = ContentType.create(contentType, ContentType.PARAMETER_IEEE754_COMPATIBLE + "=false"); - } else { - throw new IllegalArgumentException("Invalid IEEE754Compatible value " + acceptedType); - } + + final String ieee754compatibleValue = acceptedType.getParameter(ContentType.PARAMETER_IEEE754_COMPATIBLE); + if ("true".equalsIgnoreCase(ieee754compatibleValue)) { + contentType = ContentType.create(contentType, ContentType.PARAMETER_IEEE754_COMPATIBLE, "true"); + } else if ("false".equalsIgnoreCase(ieee754compatibleValue)) { + contentType = ContentType.create(contentType, ContentType.PARAMETER_IEEE754_COMPATIBLE, "false"); + } else if (ieee754compatibleValue != null) { + throw new IllegalArgumentException("Invalid IEEE754Compatible value " + ieee754compatibleValue); } - + if (acceptedType.matches(contentType)) { return contentType; } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2a841552/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchPartHandler.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchPartHandler.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchPartHandler.java index e115dcb..653fd5f 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchPartHandler.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchPartHandler.java @@ -30,7 +30,6 @@ import org.apache.olingo.server.api.deserializer.batch.ODataResponsePart; import org.apache.olingo.server.api.processor.BatchProcessor; import org.apache.olingo.server.core.ODataHandler; import org.apache.olingo.server.core.batchhandler.referenceRewriting.BatchReferenceRewriter; -import org.apache.olingo.server.core.deserializer.batch.BatchParserCommon; public class BatchPartHandler { private final ODataHandler oDataHandler; http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2a841552/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchBodyPart.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchBodyPart.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchBodyPart.java index f5d68e4..f77f886 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchBodyPart.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchBodyPart.java @@ -28,7 +28,7 @@ import org.apache.olingo.server.api.deserializer.batch.BatchDeserializerExceptio public class BatchBodyPart implements BatchPart { final private String boundary; final private boolean isStrict; - final List<Line> remainingMessage = new LinkedList<Line>(); + List<Line> remainingMessage = new LinkedList<Line>(); private Header headers; private boolean isChangeSet; @@ -49,9 +49,8 @@ public class BatchBodyPart implements BatchPart { return this; } - private boolean isChangeSet(final Header header) throws BatchDeserializerException { + private boolean isChangeSet(final Header headers) throws BatchDeserializerException { final List<String> contentTypes = headers.getHeaders(HttpHeader.CONTENT_TYPE); - boolean isChangeSet = false; if (contentTypes.isEmpty()) { throw new BatchDeserializerException("Missing content type", @@ -59,12 +58,12 @@ public class BatchBodyPart implements BatchPart { Integer.toString(headers.getLineNumber())); } + boolean isChangeSet = false; for (String contentType : contentTypes) { if (isContentTypeMultiPartMixed(contentType)) { isChangeSet = true; } } - return isChangeSet; } @@ -85,7 +84,7 @@ public class BatchBodyPart implements BatchPart { return requestList; } - private List<List<Line>> splitChangeSet(final List<Line> remainingMessage2) throws BatchDeserializerException { + private List<List<Line>> splitChangeSet(List<Line> remainingMessage) throws BatchDeserializerException { final HeaderField contentTypeField = headers.getHeaderField(HttpHeader.CONTENT_TYPE); final String changeSetBoundary = BatchParserCommon.getBoundary(contentTypeField.getValueNotNull(), http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2a841552/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchParserCommon.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchParserCommon.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchParserCommon.java index 7fd17e5..7126f14 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchParserCommon.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchParserCommon.java @@ -20,7 +20,6 @@ package org.apache.olingo.server.core.deserializer.batch; import java.io.ByteArrayInputStream; import java.io.InputStream; -import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -33,15 +32,12 @@ import org.apache.olingo.server.api.deserializer.batch.BatchDeserializerExceptio public class BatchParserCommon { - private static final String REG_EX_BOUNDARY = - "([a-zA-Z0-9_\\-\\.'\\+]{1,70})|\"([a-zA-Z0-9_\\-\\.'\\+\\s\\" + - "(\\),/:=\\?]{1,69}[a-zA-Z0-9_\\-\\.'\\+\\(\\),/:=\\?])\""; - private static final Pattern PATTERN_LAST_CRLF = Pattern.compile("(.*)(\r\n){1}( *)", Pattern.DOTALL); + private static final String PATTERN_BOUNDARY = + "([a-zA-Z0-9_\\-\\.'\\+]{1,70})|" + + "\"([a-zA-Z0-9_\\-\\.'\\+\\s\\(\\),/:=\\?]{1,69}[a-zA-Z0-9_\\-\\.'\\+\\(\\),/:=\\?])\""; + private static final Pattern PATTERN_LAST_CRLF = Pattern.compile("(.*)\\r\\n\\s*", Pattern.DOTALL); private static final Pattern PATTERN_HEADER_LINE = Pattern.compile("([a-zA-Z\\-]+):\\s?(.*)\\s*"); - protected static final String HTTP_RANGE = "Range"; - protected static final String HTTP_TE = "TE"; - public static final String CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding"; protected static final String BOUNDARY = "boundary"; @@ -49,13 +45,11 @@ public class BatchParserCommon { public static String getBoundary(final String contentType, final int line) throws BatchDeserializerException { final ContentType type = getContentType(contentType, ContentType.MULTIPART_MIXED, line); - - String boundary; final Map<String, String> parameters = type.getParameters(); for (final String parameterName : parameters.keySet()) { if (BOUNDARY.equalsIgnoreCase(parameterName)) { - boundary = parameters.get(parameterName).trim(); - if (boundary.matches(REG_EX_BOUNDARY)) { + final String boundary = parameters.get(parameterName).trim(); + if (boundary.matches(PATTERN_BOUNDARY)) { return trimQuotes(boundary); } else { throw new BatchDeserializerException("Invalid boundary format", @@ -91,9 +85,7 @@ public class BatchParserCommon { public static String removeEndingSlash(final String content) { String newContent = content.trim(); - int lastSlashIndex = newContent.lastIndexOf('/'); - - return (lastSlashIndex == newContent.length() - 1) ? newContent.substring(0, newContent.length() - 1) : newContent; + return newContent.endsWith("/") ? newContent.substring(0, newContent.length() - 1) : newContent; } private static String trimQuotes(final String boundary) { @@ -106,12 +98,12 @@ public class BatchParserCommon { public static List<List<Line>> splitMessageByBoundary(final List<Line> message, final String boundary) throws BatchDeserializerException { final List<List<Line>> messageParts = new LinkedList<List<Line>>(); - List<Line> currentPart = new ArrayList<Line>(); + List<Line> currentPart = new LinkedList<Line>(); boolean isEndReached = false; final String quotedBoundary = Pattern.quote(boundary); - final Pattern boundaryDelimiterPattern = Pattern.compile("--" + quotedBoundary + "--[\\s ]*"); - final Pattern boundaryPattern = Pattern.compile("--" + quotedBoundary + "[\\s ]*"); + final Pattern boundaryDelimiterPattern = Pattern.compile("--" + quotedBoundary + "--\\s*"); + final Pattern boundaryPattern = Pattern.compile("--" + quotedBoundary + "\\s*"); for (Line currentLine : message) { if (boundaryDelimiterPattern.matcher(currentLine.toString()).matches()) { @@ -153,9 +145,7 @@ public class BatchParserCommon { } public static Line removeEndingCRLF(final Line line) { - Pattern pattern = PATTERN_LAST_CRLF; - Matcher matcher = pattern.matcher(line.toString()); - + Matcher matcher = PATTERN_LAST_CRLF.matcher(line.toString()); if (matcher.matches()) { return new Line(matcher.group(1), line.getLineNumber()); } else { @@ -191,7 +181,7 @@ public class BatchParserCommon { public static void consumeBlankLine(List<Line> remainingMessage, final boolean isStrict) throws BatchDeserializerException { - if (remainingMessage.size() > 0 && remainingMessage.get(0).toString().matches("\\s*(\r\n|\n)\\s*")) { + if (remainingMessage.size() > 0 && remainingMessage.get(0).toString().matches("\\s*\r?\n\\s*")) { remainingMessage.remove(0); } else { if (isStrict) { http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2a841552/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchRequestTransformator.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchRequestTransformator.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchRequestTransformator.java index 57ecfbe..ce46839 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchRequestTransformator.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchRequestTransformator.java @@ -129,7 +129,7 @@ public class BatchRequestTransformator { if (header.exists(HttpHeader.AUTHORIZATION) || header.exists(HttpHeader.EXPECT) || header.exists(HttpHeader.FROM) || header.exists(HttpHeader.MAX_FORWARDS) - || header.exists(BatchParserCommon.HTTP_RANGE) || header.exists(BatchParserCommon.HTTP_TE)) { + || header.exists(HttpHeader.RANGE) || header.exists(HttpHeader.TE)) { throw new BatchDeserializerException("Forbidden header", MessageKeys.FORBIDDEN_HEADER, Integer.toString(header.getLineNumber())); } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2a841552/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializer.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializer.java index c67efbc..71e5030 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializer.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializer.java @@ -78,11 +78,11 @@ public class ODataJsonDeserializer implements ODataDeserializer { private static final EdmPrimitiveType EDM_INT64 = EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Int64); private static final EdmPrimitiveType EDM_DECIMAL = EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal); private final boolean isIEEE754Compatible; - + public ODataJsonDeserializer(final ContentType contentType) { isIEEE754Compatible = isODataIEEE754Compatible(contentType); } - + @Override public DeserializerResult entityCollection(final InputStream stream, final EdmEntityType edmEntityType) throws DeserializerException { @@ -248,7 +248,7 @@ public class ODataJsonDeserializer implements ODataDeserializer { private void consumeParameters(final EdmAction edmAction, final ObjectNode node, final Map<String, Parameter> parameters) - throws DeserializerException { + throws DeserializerException { List<String> parameterNames = edmAction.getParameterNames(); if (edmAction.isBound()) { // The binding parameter must not occur in the payload. @@ -489,7 +489,7 @@ public class ODataJsonDeserializer implements ODataDeserializer { private Object readComplexNode(final String name, final EdmType type, final boolean isNullable, final JsonNode jsonNode) - throws DeserializerException { + throws DeserializerException { // read and add all complex properties ComplexValue value = readComplexValue(name, type, isNullable, jsonNode); @@ -674,15 +674,15 @@ public class ODataJsonDeserializer implements ODataDeserializer { checkJsonTypeBasedOnPrimitiveType(name, edmPrimitiveType.getName(), jsonNode); Class<?> javaClass = getJavaClassForPrimitiveType(mapping, edmPrimitiveType); String jsonNodeAsText = jsonNode.asText(); - + if (isIEEE754Compatible && (edmPrimitiveType.equals(EDM_INT64) || edmPrimitiveType.equals(EDM_DECIMAL))) { - if(jsonNodeAsText.length() == 0) { - throw new DeserializerException("IEEE754Compatible values must not be of length 0", + if (jsonNodeAsText.length() == 0) { + throw new DeserializerException("IEEE754Compatible values must not be of length 0", MessageKeys.INVALID_NULL_PROPERTY, name); } } - - return edmPrimitiveType.valueOfString(jsonNodeAsText, isNullable, maxLength, precision, scale, isUnicode, + + return edmPrimitiveType.valueOfString(jsonNodeAsText, isNullable, maxLength, precision, scale, isUnicode, javaClass); } catch (EdmPrimitiveTypeException e) { throw new DeserializerException( @@ -734,7 +734,7 @@ public class ODataJsonDeserializer implements ODataDeserializer { private void checkJsonTypeBasedOnPrimitiveType(final String propertyName, final String edmPrimitiveTypeName, final JsonNode jsonNode) - throws DeserializerException { + throws DeserializerException { EdmPrimitiveTypeKind primKind; try { primKind = EdmPrimitiveTypeKind.valueOf(edmPrimitiveTypeName); @@ -765,15 +765,17 @@ public class ODataJsonDeserializer implements ODataDeserializer { case Int64: case Decimal: // Numbers (eighter numers or string) - if(isIEEE754Compatible) { + if (isIEEE754Compatible) { if (!jsonNode.isTextual()) { throw new DeserializerException("Invalid json type: " + jsonNode.getNodeType() + " for edm " + primKind - + " property: " + propertyName, DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, propertyName); + + " property: " + propertyName, DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, + propertyName); } } else { if (!jsonNode.isNumber()) { throw new DeserializerException("Invalid json type: " + jsonNode.getNodeType() + " for edm " + primKind - + " property: " + propertyName, DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, propertyName); + + " property: " + propertyName, DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, + propertyName); } } break; @@ -849,7 +851,7 @@ public class ODataJsonDeserializer implements ODataDeserializer { Iterator<JsonNode> it = arrayNode.iterator(); while (it.hasNext()) { final JsonNode next = it.next(); - if(next.has(key)) { + if (next.has(key)) { parsedValues.add(new URI(next.get(key).asText())); } } @@ -860,7 +862,7 @@ public class ODataJsonDeserializer implements ODataDeserializer { // if this is value there can be only one property return DeserializerResultImpl.with().entityReferences(parsedValues).build(); } - if(tree.get(key) != null) { + if (tree.get(key) != null) { parsedValues.add(new URI(tree.get(key).asText())); } else { throw new DeserializerException("Missing entity reference", DeserializerException.MessageKeys.UNKNOWN_CONTENT); @@ -880,10 +882,10 @@ public class ODataJsonDeserializer implements ODataDeserializer { DeserializerException.MessageKeys.UNKNOWN_CONTENT); } } - + private boolean isODataIEEE754Compatible(final ContentType contentType) { - return contentType.getParameters().containsKey(ContentType.PARAMETER_IEEE754_COMPATIBLE) - && Boolean.TRUE.toString().toLowerCase().equals( - contentType.getParameter(ContentType.PARAMETER_IEEE754_COMPATIBLE).toLowerCase()); + return contentType.getParameters().containsKey(ContentType.PARAMETER_IEEE754_COMPATIBLE) + && Boolean.TRUE.toString().equalsIgnoreCase( + contentType.getParameter(ContentType.PARAMETER_IEEE754_COMPATIBLE)); } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2a841552/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java index f50fcad..e9d4858 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java @@ -75,12 +75,12 @@ public class ODataJsonSerializer implements ODataSerializer { private static final Logger log = LoggerFactory.getLogger(ODataJsonSerializer.class); - private final ContentType contentType; private final boolean isIEEE754Compatible; - + private final boolean isODataMetadataNone; + public ODataJsonSerializer(final ContentType contentType) { this.isIEEE754Compatible = isODataIEEE754Compatible(contentType); - this.contentType = contentType; + this.isODataMetadataNone = ContentTypeHelper.isODataMetadataNone(contentType); } @Override @@ -94,7 +94,7 @@ public class ODataJsonSerializer implements ODataSerializer { gen = new JsonFactory().createGenerator(buffer.getOutputStream()) .setPrettyPrinter(new DefaultPrettyPrinter()); - new ServiceDocumentJsonSerializer(metadata, serviceRoot, contentType).writeServiceDocument(gen); + new ServiceDocumentJsonSerializer(metadata, serviceRoot, isODataMetadataNone).writeServiceDocument(gen); gen.close(); @@ -146,15 +146,11 @@ public class ODataJsonSerializer implements ODataSerializer { json.writeStartObject(); final ContextURL contextURL = checkContextURL(options == null ? null : options.getContextURL()); - if (contextURL != null) { - json.writeStringField(Constants.JSON_CONTEXT, - ContextURLBuilder.create(contextURL).toASCIIString()); - } + writeContextURL(contextURL, json); writeMetadataETag(metadata, json); - if (options != null && options.getCount() != null && options.getCount().getValue() - && entitySet.getCount() != null) { + if (options != null && options.getCount() != null && options.getCount().getValue()) { writeCount(entitySet, json); } json.writeFieldName(Constants.VALUE); @@ -164,9 +160,7 @@ public class ODataJsonSerializer implements ODataSerializer { writeEntitySet(metadata, entityType, entitySet, options.getExpand(), options.getSelect(), options.onlyReferences(), json); } - if (entitySet.getNext() != null) { - writeNextLink(entitySet, json); - } + writeNextLink(entitySet, json); json.close(); } catch (final IOException e) { throw new SerializerException("An I/O exception occurred.", e, @@ -196,7 +190,7 @@ public class ODataJsonSerializer implements ODataSerializer { } private ContextURL checkContextURL(final ContextURL contextURL) throws SerializerException { - if(ContentTypeHelper.isODataMetadataNone(contentType)) { + if (isODataMetadataNone) { return null; } else if (contextURL == null) { throw new SerializerException("ContextURL null!", SerializerException.MessageKeys.NO_CONTEXT_URL); @@ -204,16 +198,6 @@ public class ODataJsonSerializer implements ODataSerializer { return contextURL; } - private void writeMetadataETag(final ServiceMetadata metadata, JsonGenerator json) throws IOException { - if (!ContentTypeHelper.isODataMetadataNone(contentType) - && metadata != null - && metadata.getServiceMetadataETagSupport() != null - && metadata.getServiceMetadataETagSupport().getMetadataETag() != null) { - json.writeStringField(Constants.JSON_METADATA_ETAG, - metadata.getServiceMetadataETagSupport().getMetadataETag()); - } - } - protected void writeEntitySet(final ServiceMetadata metadata, final EdmEntityType entityType, final EntityCollection entitySet, final ExpandOption expand, final SelectOption select, final boolean onlyReference, final JsonGenerator json) throws IOException, @@ -233,12 +217,12 @@ public class ODataJsonSerializer implements ODataSerializer { protected void writeEntity(final ServiceMetadata metadata, final EdmEntityType entityType, final Entity entity, final ContextURL contextURL, final ExpandOption expand, - final SelectOption select, final boolean onlyReference, final JsonGenerator json) - throws IOException, SerializerException { + final SelectOption select, final boolean onlyReference, final JsonGenerator json) + throws IOException, SerializerException { json.writeStartObject(); - if(!ContentTypeHelper.isODataMetadataNone(contentType)) { + if (!isODataMetadataNone) { if (contextURL != null) { // top-level entity - json.writeStringField(Constants.JSON_CONTEXT, ContextURLBuilder.create(contextURL).toASCIIString()); + writeContextURL(contextURL, json); writeMetadataETag(metadata, json); } if (entity.getETag() != null) { @@ -262,8 +246,8 @@ public class ODataJsonSerializer implements ODataSerializer { if (onlyReference) { json.writeStringField(Constants.JSON_ID, entity.getId().toASCIIString()); } else { - EdmEntityType resolvedType = resolveEntityType(metadata, entityType, entity.getType()); - if (!resolvedType.equals(entityType)) { + final EdmEntityType resolvedType = resolveEntityType(metadata, entityType, entity.getType()); + if (!isODataMetadataNone && !resolvedType.equals(entityType)) { json.writeStringField(Constants.JSON_TYPE, "#" + entity.getType()); } writeProperties(resolvedType, entity.getProperties(), select, json); @@ -321,8 +305,8 @@ public class ODataJsonSerializer implements ODataSerializer { } protected void writeProperties(final EdmStructuredType type, final List<Property> properties, - final SelectOption select, final JsonGenerator json) - throws IOException, SerializerException { + final SelectOption select, final JsonGenerator json) + throws IOException, SerializerException { final boolean all = ExpandSelectHelper.isAll(select); final Set<String> selected = all ? null : ExpandSelectHelper.getSelectedPropertyNames(select.getSelectItems()); @@ -362,8 +346,8 @@ public class ODataJsonSerializer implements ODataSerializer { } } - protected void writeExpandedNavigationProperty(final ServiceMetadata metadata, final EdmNavigationProperty property, - final Link navigationLink, final ExpandOption innerExpand, final SelectOption innerSelect, + protected void writeExpandedNavigationProperty(final ServiceMetadata metadata, final EdmNavigationProperty property, + final Link navigationLink, final ExpandOption innerExpand, final SelectOption innerSelect, final JsonGenerator json) throws IOException, SerializerException { json.writeFieldName(property.getName()); if (property.isCollection()) { @@ -385,8 +369,8 @@ public class ODataJsonSerializer implements ODataSerializer { } protected void writeProperty(final EdmProperty edmProperty, final Property property, - final Set<List<String>> selectedPaths, final JsonGenerator json) - throws IOException, SerializerException { + final Set<List<String>> selectedPaths, final JsonGenerator json) + throws IOException, SerializerException { json.writeFieldName(edmProperty.getName()); if (property == null || property.isNull()) { if (edmProperty.isNullable() == Boolean.FALSE) { @@ -401,8 +385,8 @@ public class ODataJsonSerializer implements ODataSerializer { } private void writePropertyValue(final EdmProperty edmProperty, - final Property property, final Set<List<String>> selectedPaths, final JsonGenerator json) - throws IOException, SerializerException { + final Property property, final Set<List<String>> selectedPaths, final JsonGenerator json) + throws IOException, SerializerException { try { if (edmProperty.isPrimitive()) { if (edmProperty.isCollection()) { @@ -435,8 +419,8 @@ public class ODataJsonSerializer implements ODataSerializer { private void writePrimitiveCollection(final EdmPrimitiveType type, final Property property, final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale, - final Boolean isUnicode, final JsonGenerator json) - throws IOException, EdmPrimitiveTypeException, SerializerException { + final Boolean isUnicode, final JsonGenerator json) + throws IOException, EdmPrimitiveTypeException, SerializerException { json.writeStartArray(); for (Object value : property.asCollection()) { switch (property.getValueType()) { @@ -500,20 +484,17 @@ public class ODataJsonSerializer implements ODataSerializer { isNullable, maxLength, precision, scale, isUnicode); if (value == null) { json.writeNull(); - } else if(type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Boolean)) { - json.writeBoolean(Boolean.parseBoolean(value)); - } else if(isIEEE754Compatible && - ( type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Int64) - || type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal))) { - json.writeString(value.toString()); + } else if (type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Boolean)) { + json.writeBoolean(Boolean.parseBoolean(value)); } else if (type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Byte) - || type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal) || type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Double) || type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Int16) || type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Int32) - || type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Int64) || type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.SByte) - || type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Single)) { + || type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Single) + || (type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal) + || type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Int64)) + && !isIEEE754Compatible) { json.writeNumber(value); } else { json.writeString(value); @@ -552,17 +533,18 @@ public class ODataJsonSerializer implements ODataSerializer { try { JsonGenerator json = new JsonFactory().createGenerator(buffer.getOutputStream()); json.writeStartObject(); - if (contextURL != null) { - json.writeStringField(Constants.JSON_CONTEXT, ContextURLBuilder.create(contextURL).toASCIIString()); - } + writeContextURL(contextURL, json); writeMetadataETag(metadata, json); if (property.isNull()) { throw new SerializerException("Property value can not be null.", SerializerException.MessageKeys.NULL_INPUT); } else { json.writeFieldName(Constants.VALUE); writePrimitive(type, property, - options.isNullable(), options.getMaxLength(), options.getPrecision(), options.getScale(), - options.isUnicode(), json); + options == null ? null : options.isNullable(), + options == null ? null : options.getMaxLength(), + options == null ? null : options.getPrecision(), + options == null ? null : options.getScale(), + options == null ? null : options.isUnicode(), json); } json.writeEndObject(); json.close(); @@ -585,12 +567,10 @@ public class ODataJsonSerializer implements ODataSerializer { try { JsonGenerator json = new JsonFactory().createGenerator(buffer.getOutputStream()); json.writeStartObject(); - if (contextURL != null) { - json.writeStringField(Constants.JSON_CONTEXT, ContextURLBuilder.create(contextURL).toASCIIString()); - } + writeContextURL(contextURL, json); writeMetadataETag(metadata, json); - EdmComplexType resolvedType = resolveComplexType(metadata, type, property.getType()); - if (!resolvedType.equals(type)) { + final EdmComplexType resolvedType = resolveComplexType(metadata, type, property.getType()); + if (!isODataMetadataNone && !resolvedType.equals(type)) { json.writeStringField(Constants.JSON_TYPE, "#" + property.getType()); } final List<Property> values = @@ -617,14 +597,15 @@ public class ODataJsonSerializer implements ODataSerializer { try { JsonGenerator json = new JsonFactory().createGenerator(buffer.getOutputStream()); json.writeStartObject(); - if (contextURL != null) { - json.writeStringField(Constants.JSON_CONTEXT, ContextURLBuilder.create(contextURL).toASCIIString()); - } + writeContextURL(contextURL, json); writeMetadataETag(metadata, json); json.writeFieldName(Constants.VALUE); writePrimitiveCollection(type, property, - options.isNullable(), options.getMaxLength(), options.getPrecision(), options.getScale(), - options.isUnicode(), json); + options == null ? null : options.isNullable(), + options == null ? null : options.getMaxLength(), + options == null ? null : options.getPrecision(), + options == null ? null : options.getScale(), + options == null ? null : options.isUnicode(), json); json.writeEndObject(); json.close(); } catch (final IOException e) { @@ -646,9 +627,7 @@ public class ODataJsonSerializer implements ODataSerializer { try { JsonGenerator json = new JsonFactory().createGenerator(buffer.getOutputStream()); json.writeStartObject(); - if (contextURL != null) { - json.writeStringField(Constants.JSON_CONTEXT, ContextURLBuilder.create(contextURL).toASCIIString()); - } + writeContextURL(contextURL, json); writeMetadataETag(metadata, json); json.writeFieldName(Constants.VALUE); writeComplexCollection(type, property, null, json); @@ -666,95 +645,100 @@ public class ODataJsonSerializer implements ODataSerializer { } @Override - public SerializerResult reference(final ServiceMetadata metadata, final EdmEntitySet edmEntitySet, + public SerializerResult reference(final ServiceMetadata metadata, final EdmEntitySet edmEntitySet, final Entity entity, final ReferenceSerializerOptions options) throws SerializerException { final ContextURL contextURL = checkContextURL(options == null ? null : options.getContextURL()); final CircleStreamBuffer buffer = new CircleStreamBuffer(); final UriHelper uriHelper = new UriHelperImpl(); - + try { final JsonGenerator json = new JsonFactory().createGenerator(buffer.getOutputStream()); - writeReference(metadata, edmEntitySet, entity, contextURL, uriHelper, json); + + json.writeStartObject(); + writeContextURL(contextURL, json); + writeMetadataETag(metadata, json); + json.writeStringField(Constants.JSON_ID, uriHelper.buildCanonicalURL(edmEntitySet, entity)); + json.writeEndObject(); json.close(); } catch (IOException e) { - throw new SerializerException("An I/O exception occurred.", e, SerializerException.MessageKeys.IO_EXCEPTION); + throw new SerializerException("An I/O exception occurred.", e, SerializerException.MessageKeys.IO_EXCEPTION); } - + return SerializerResultImpl.with().content(buffer.getInputStream()).build(); } - + @Override - public SerializerResult referenceCollection(final ServiceMetadata metadata, final EdmEntitySet edmEntitySet, - final EntityCollection entityCollection, final ReferenceCollectionSerializerOptions options) - throws SerializerException { + public SerializerResult referenceCollection(final ServiceMetadata metadata, final EdmEntitySet edmEntitySet, + final EntityCollection entityCollection, final ReferenceCollectionSerializerOptions options) + throws SerializerException { final ContextURL contextURL = checkContextURL(options == null ? null : options.getContextURL()); final CircleStreamBuffer buffer = new CircleStreamBuffer(); final UriHelper uriHelper = new UriHelperImpl(); - + try { final JsonGenerator json = new JsonFactory().createGenerator(buffer.getOutputStream()); json.writeStartObject(); - - json.writeStringField(Constants.JSON_CONTEXT, ContextURLBuilder.create(contextURL).toASCIIString()); + + writeContextURL(contextURL, json); writeMetadataETag(metadata, json); - if(options != null && options.getCount() != null) { + if (options != null && options.getCount() != null && options.getCount().getValue()) { writeCount(entityCollection, json); } - - writeReferenceCollection(edmEntitySet, entityCollection, uriHelper,json); - if(entityCollection.getNext() != null) { - writeNextLink(entityCollection, json); + json.writeArrayFieldStart(Constants.VALUE); + for (final Entity entity : entityCollection.getEntities()) { + json.writeStartObject(); + json.writeStringField(Constants.JSON_ID, uriHelper.buildCanonicalURL(edmEntitySet, entity)); + json.writeEndObject(); } - + json.writeEndArray(); + + writeNextLink(entityCollection, json); + json.writeEndObject(); json.close(); } catch (IOException e) { - throw new SerializerException("An I/O exception occurred.", e, SerializerException.MessageKeys.IO_EXCEPTION); + throw new SerializerException("An I/O exception occurred.", e, SerializerException.MessageKeys.IO_EXCEPTION); } - + return SerializerResultImpl.with().content(buffer.getInputStream()).build(); } - protected void writeReferenceCollection(final EdmEntitySet edmEntitySet, final EntityCollection entityCollection, - final UriHelper uriHelper, final JsonGenerator json) throws IOException, SerializerException { - json.writeArrayFieldStart(Constants.VALUE); - - for(final Entity entity : entityCollection.getEntities()) { - writeReference(null, edmEntitySet, entity, null, uriHelper, json); - } - - json.writeEndArray(); - } - - protected void writeReference(final ServiceMetadata metadata, final EdmEntitySet edmEntitySet, final Entity entity, - final ContextURL contextURL, final UriHelper uriHelper, final JsonGenerator json) - throws IOException, SerializerException { - json.writeStartObject(); - if (contextURL != null) { + private void writeContextURL(final ContextURL contextURL, JsonGenerator json) throws IOException { + if (!isODataMetadataNone && contextURL != null) { json.writeStringField(Constants.JSON_CONTEXT, ContextURLBuilder.create(contextURL).toASCIIString()); - writeMetadataETag(metadata, json); } + } - json.writeStringField(Constants.JSON_ID, uriHelper.buildCanonicalURL(edmEntitySet, entity)); - json.writeEndObject(); + private void writeMetadataETag(final ServiceMetadata metadata, JsonGenerator json) throws IOException { + if (!isODataMetadataNone + && metadata != null + && metadata.getServiceMetadataETagSupport() != null + && metadata.getServiceMetadataETagSupport().getMetadataETag() != null) { + json.writeStringField(Constants.JSON_METADATA_ETAG, + metadata.getServiceMetadataETagSupport().getMetadataETag()); + } } - - private void writeCount(final EntityCollection entitySet, final JsonGenerator json) throws IOException { - if(isIEEE754Compatible) { - json.writeStringField(Constants.JSON_COUNT, entitySet.getCount().toString()); - } else { - json.writeNumberField(Constants.JSON_COUNT, entitySet.getCount()); + + private void writeCount(final EntityCollection entityCollection, JsonGenerator json) throws IOException { + if (entityCollection.getCount() != null) { + if (isIEEE754Compatible) { + json.writeStringField(Constants.JSON_COUNT, entityCollection.getCount().toString()); + } else { + json.writeNumberField(Constants.JSON_COUNT, entityCollection.getCount()); + } } } private void writeNextLink(final EntityCollection entitySet, JsonGenerator json) throws IOException { - json.writeStringField(Constants.JSON_NEXT_LINK, entitySet.getNext().toASCIIString()); + if (entitySet.getNext() != null) { + json.writeStringField(Constants.JSON_NEXT_LINK, entitySet.getNext().toASCIIString()); + } } - + private boolean isODataIEEE754Compatible(final ContentType contentType) { - return contentType.getParameters().containsKey(ContentType.PARAMETER_IEEE754_COMPATIBLE) + return contentType.getParameters().containsKey(ContentType.PARAMETER_IEEE754_COMPATIBLE) && Boolean.TRUE.toString().toLowerCase().equals( contentType.getParameter(ContentType.PARAMETER_IEEE754_COMPATIBLE).toLowerCase()); } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2a841552/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ServiceDocumentJsonSerializer.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ServiceDocumentJsonSerializer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ServiceDocumentJsonSerializer.java index 5b34184..30162c1 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ServiceDocumentJsonSerializer.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ServiceDocumentJsonSerializer.java @@ -26,9 +26,7 @@ import org.apache.olingo.commons.api.edm.EdmEntityContainer; import org.apache.olingo.commons.api.edm.EdmEntitySet; import org.apache.olingo.commons.api.edm.EdmFunctionImport; import org.apache.olingo.commons.api.edm.EdmSingleton; -import org.apache.olingo.commons.api.format.ContentType; import org.apache.olingo.server.api.ServiceMetadata; -import org.apache.olingo.server.core.serializer.utils.ContentTypeHelper; import com.fasterxml.jackson.core.JsonGenerator; @@ -41,30 +39,31 @@ public class ServiceDocumentJsonSerializer { private final ServiceMetadata metadata; private final String serviceRoot; - private final ContentType contentType; + private final boolean isODataMetadataNone; public ServiceDocumentJsonSerializer(final ServiceMetadata metadata, final String serviceRoot, - final ContentType contentType) { + final boolean isODataMetadataNone) { this.metadata = metadata; this.serviceRoot = serviceRoot; - this.contentType = contentType; + this.isODataMetadataNone = isODataMetadataNone; } public void writeServiceDocument(final JsonGenerator gen) throws IOException { gen.writeStartObject(); - final String metadataUri = - (serviceRoot == null ? "" : - serviceRoot.endsWith("/") ? serviceRoot : (serviceRoot + "/")) - + Constants.METADATA; - gen.writeObjectField(Constants.JSON_CONTEXT, metadataUri); - - if (!ContentTypeHelper.isODataMetadataNone(contentType) - && metadata != null - && metadata.getServiceMetadataETagSupport() != null - && metadata.getServiceMetadataETagSupport().getMetadataETag() != null) { - gen.writeStringField(Constants.JSON_METADATA_ETAG, - metadata.getServiceMetadataETagSupport().getMetadataETag()); + if (!isODataMetadataNone) { + final String metadataUri = + (serviceRoot == null ? "" : + serviceRoot.endsWith("/") ? serviceRoot : (serviceRoot + "/")) + + Constants.METADATA; + gen.writeObjectField(Constants.JSON_CONTEXT, metadataUri); + + if (metadata != null + && metadata.getServiceMetadataETagSupport() != null + && metadata.getServiceMetadataETagSupport().getMetadataETag() != null) { + gen.writeStringField(Constants.JSON_METADATA_ETAG, + metadata.getServiceMetadataETagSupport().getMetadataETag()); + } } gen.writeArrayFieldStart(Constants.VALUE); http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2a841552/lib/server-core/src/test/java/org/apache/olingo/server/core/ContentNegotiatorTest.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/ContentNegotiatorTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/ContentNegotiatorTest.java index 07e06ca..d4af42a 100644 --- a/lib/server-core/src/test/java/org/apache/olingo/server/core/ContentNegotiatorTest.java +++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/ContentNegotiatorTest.java @@ -165,7 +165,8 @@ public class ContentNegotiatorTest { ContentNegotiator.checkSupport(ContentType.create("a/b"), createCustomContentTypeSupport("a/b"), RepresentationType.ENTITY); - ContentNegotiator.checkSupport(ContentType.create("a/b", "c=d"), createCustomContentTypeSupport("a/b"), + ContentNegotiator.checkSupport(ContentType.create(ContentType.create("a/b"), "c", "d"), + createCustomContentTypeSupport("a/b"), RepresentationType.ENTITY); try { ContentNegotiator.checkSupport(ContentType.create("a/b"), createCustomContentTypeSupport("a/b;c=d"), http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2a841552/lib/server-core/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerBasicTest.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerBasicTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerBasicTest.java index d29fdf8..c73acab 100644 --- a/lib/server-core/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerBasicTest.java +++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerBasicTest.java @@ -33,7 +33,7 @@ import org.apache.olingo.server.api.deserializer.ODataDeserializer; import org.junit.Test; public class ODataJsonDeserializerBasicTest { - + @Test public void checkSupportedJsonFormats() throws Exception { ODataDeserializer deserializer = OData.newInstance().createDeserializer(ContentType.JSON); @@ -78,7 +78,7 @@ public class ODataJsonDeserializerBasicTest { assertEquals(1, values.size()); assertEquals("Orders(10643)", values.get(0).toASCIIString()); } - + @Test public void reference() throws Exception { String entityString = "{" @@ -89,82 +89,82 @@ public class ODataJsonDeserializerBasicTest { InputStream stream = new ByteArrayInputStream(entityString.getBytes()); ODataDeserializer deserializer = OData.newInstance().createDeserializer(ContentType.JSON); final List<URI> entityReferences = deserializer.entityReferences(stream).getEntityReferences(); - + assertEquals(1, entityReferences.size()); assertEquals("ESAllPrim(0)", entityReferences.get(0).toASCIIString()); } - + @Test public void references() throws Exception { - String entityString = "{" + - " \"@odata.context\": \"$metadata#Collection($ref)\"," + - " \"value\": [" + - " { \"@odata.id\": \"ESAllPrim(0)\" }," + - " { \"@odata.id\": \"ESAllPrim(1)\" }" + - " ]" + + String entityString = "{" + + " \"@odata.context\": \"$metadata#Collection($ref)\"," + + " \"value\": [" + + " { \"@odata.id\": \"ESAllPrim(0)\" }," + + " { \"@odata.id\": \"ESAllPrim(1)\" }" + + " ]" + "}"; InputStream stream = new ByteArrayInputStream(entityString.getBytes()); ODataDeserializer deserializer = OData.newInstance().createDeserializer(ContentType.JSON); final List<URI> entityReferences = deserializer.entityReferences(stream).getEntityReferences(); - + assertEquals(2, entityReferences.size()); assertEquals("ESAllPrim(0)", entityReferences.get(0).toASCIIString()); assertEquals("ESAllPrim(1)", entityReferences.get(1).toASCIIString()); } - + @Test public void referencesWithOtherAnnotations() throws Exception { - String entityString = "{" + - " \"@odata.context\": \"$metadata#Collection($ref)\"," + - " \"value\": [" + - " { \"@odata.id\": \"ESAllPrim(0)\" }," + - " { \"@odata.nonExistingODataAnnotation\": \"ESAllPrim(1)\" }" + - " ]" + + String entityString = "{" + + " \"@odata.context\": \"$metadata#Collection($ref)\"," + + " \"value\": [" + + " { \"@odata.id\": \"ESAllPrim(0)\" }," + + " { \"@odata.nonExistingODataAnnotation\": \"ESAllPrim(1)\" }" + + " ]" + "}"; InputStream stream = new ByteArrayInputStream(entityString.getBytes()); ODataDeserializer deserializer = OData.newInstance().createDeserializer(ContentType.JSON); final List<URI> entityReferences = deserializer.entityReferences(stream).getEntityReferences(); - + assertEquals(1, entityReferences.size()); assertEquals("ESAllPrim(0)", entityReferences.get(0).toASCIIString()); } - + @Test public void referencesWithCustomAnnotation() throws Exception { - String entityString = "{" + - " \"@odata.context\": \"$metadata#Collection($ref)\"," + - " \"value\": [" + - " { \"@odata.id\": \"ESAllPrim(0)\" }," + - " { \"@invalid\": \"ESAllPrim(1)\" }" + - " ]" + + String entityString = "{" + + " \"@odata.context\": \"$metadata#Collection($ref)\"," + + " \"value\": [" + + " { \"@odata.id\": \"ESAllPrim(0)\" }," + + " { \"@invalid\": \"ESAllPrim(1)\" }" + + " ]" + "}"; InputStream stream = new ByteArrayInputStream(entityString.getBytes()); ODataDeserializer deserializer = OData.newInstance().createDeserializer(ContentType.JSON); final List<URI> entityReferences = deserializer.entityReferences(stream).getEntityReferences(); - + assertEquals(1, entityReferences.size()); assertEquals("ESAllPrim(0)", entityReferences.get(0).toASCIIString()); } - + @Test public void referenceEmpty() throws Exception { - String entityString = "{" + - " \"@odata.context\": \"$metadata#Collection($ref)\"," + - " \"value\": [" + - " ]" + + String entityString = "{" + + " \"@odata.context\": \"$metadata#Collection($ref)\"," + + " \"value\": [" + + " ]" + "}"; InputStream stream = new ByteArrayInputStream(entityString.getBytes()); ODataDeserializer deserializer = OData.newInstance().createDeserializer(ContentType.JSON); final List<URI> entityReferences = deserializer.entityReferences(stream).getEntityReferences(); - + assertEquals(0, entityReferences.size()); } - - @Test(expected=DeserializerException.class) + + @Test(expected = DeserializerException.class) public void referencesEmpty() throws Exception { /* * See OData JSON Format chaper 13 @@ -175,15 +175,15 @@ public class ODataJsonDeserializerBasicTest { InputStream stream = new ByteArrayInputStream(entityString.getBytes()); ODataDeserializer deserializer = OData.newInstance().createDeserializer(ContentType.JSON); final List<URI> entityReferences = deserializer.entityReferences(stream).getEntityReferences(); - + assertEquals(0, entityReferences.size()); } - - @Test(expected=DeserializerException.class) + + @Test(expected = DeserializerException.class) public void referenceValueIsNotAnArray() throws Exception { - String entityString = "{" + - " \"@odata.context\": \"$metadata#Collection($ref)\"," + - " \"value\": \"ESAllPrim(0)\"" + // This is not allowed. Value must be followed by an array + String entityString = "{" + + " \"@odata.context\": \"$metadata#Collection($ref)\"," + + " \"value\": \"ESAllPrim(0)\"" + // This is not allowed. Value must be followed by an array "}"; InputStream stream = new ByteArrayInputStream(entityString.getBytes()); http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2a841552/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java ---------------------------------------------------------------------- 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 64327f3..e9761dc 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 @@ -255,9 +255,10 @@ public abstract class TechnicalProcessor implements Processor { HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT); } } - + protected boolean isODataMetadataNone(final ContentType contentType) { - return contentType.isCompatible(ContentType.APPLICATION_JSON) - && ContentType.VALUE_ODATA_METADATA_NONE.equals(contentType.getParameter(ContentType.PARAMETER_ODATA_METADATA)); + return contentType.isCompatible(ContentType.APPLICATION_JSON) + && ContentType.VALUE_ODATA_METADATA_NONE.equals( + contentType.getParameter(ContentType.PARAMETER_ODATA_METADATA)); } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2a841552/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerEntityTest.java ---------------------------------------------------------------------- diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerEntityTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerEntityTest.java index 4684461..4a03b03 100644 --- a/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerEntityTest.java +++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerEntityTest.java @@ -1411,7 +1411,7 @@ public class ODataJsonDeserializerEntityTest extends AbstractODataDeserializerTe throw e; } } - + @Test public void ieee754Compatible() throws Exception { ODataDeserializer deserializer = OData.newInstance().createDeserializer(CONTENT_TYPE_JSON_IEEE754Compatible); @@ -1432,15 +1432,15 @@ public class ODataJsonDeserializerEntityTest extends AbstractODataDeserializerTe "\"PropertyDuration\":\"PT6S\"," + "\"PropertyGuid\":\"01234567-89ab-cdef-0123-456789abcdef\"," + "\"PropertyTimeOfDay\":\"03:26:05\"}"; - + final InputStream stream = new ByteArrayInputStream(entityString.getBytes()); final Entity entity = deserializer .entity(stream, edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETAllPrim"))).getEntity(); - + assertEquals(9223372036854775807L, entity.getProperty("PropertyInt64").asPrimitive()); assertEquals(BigDecimal.valueOf(34), entity.getProperty("PropertyDecimal").asPrimitive()); } - + @Test public void ieee754CompatibleNull() throws Exception { ODataDeserializer deserializer = OData.newInstance().createDeserializer(CONTENT_TYPE_JSON_IEEE754Compatible); @@ -1461,16 +1461,16 @@ public class ODataJsonDeserializerEntityTest extends AbstractODataDeserializerTe "\"PropertyDuration\":\"PT6S\"," + "\"PropertyGuid\":\"01234567-89ab-cdef-0123-456789abcdef\"," + "\"PropertyTimeOfDay\":\"03:26:05\"}"; - + final InputStream stream = new ByteArrayInputStream(entityString.getBytes()); final Entity entity = deserializer .entity(stream, edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETAllPrim"))).getEntity(); - + assertTrue(entity.getProperty("PropertyInt64").isNull()); assertTrue(entity.getProperty("PropertyDecimal").isNull()); } - - @Test(expected=DeserializerException.class) + + @Test(expected = DeserializerException.class) public void ieee754CompatibleEmptyString() throws Exception { ODataDeserializer deserializer = OData.newInstance().createDeserializer(CONTENT_TYPE_JSON_IEEE754Compatible); String entityString = @@ -1490,12 +1490,12 @@ public class ODataJsonDeserializerEntityTest extends AbstractODataDeserializerTe "\"PropertyDuration\":\"PT6S\"," + "\"PropertyGuid\":\"01234567-89ab-cdef-0123-456789abcdef\"," + "\"PropertyTimeOfDay\":\"03:26:05\"}"; - + final InputStream stream = new ByteArrayInputStream(entityString.getBytes()); deserializer.entity(stream, edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETAllPrim"))).getEntity(); } - - @Test(expected=DeserializerException.class) + + @Test(expected = DeserializerException.class) public void ieee754CompatibleNullAsString() throws Exception { ODataDeserializer deserializer = OData.newInstance().createDeserializer(CONTENT_TYPE_JSON_IEEE754Compatible); String entityString = @@ -1515,11 +1515,11 @@ public class ODataJsonDeserializerEntityTest extends AbstractODataDeserializerTe "\"PropertyDuration\":\"PT6S\"," + "\"PropertyGuid\":\"01234567-89ab-cdef-0123-456789abcdef\"," + "\"PropertyTimeOfDay\":\"03:26:05\"}"; - + final InputStream stream = new ByteArrayInputStream(entityString.getBytes()); deserializer.entity(stream, edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETAllPrim"))).getEntity(); } - + private void checkPropertyJsonType(final String entityString) throws DeserializerException { InputStream stream = new ByteArrayInputStream(entityString.getBytes()); ODataDeserializer deserializer = OData.newInstance().createDeserializer(CONTENT_TYPE_JSON);
