You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ch...@apache.org on 2015/11/19 15:50:40 UTC

olingo-odata4 git commit: [OLINGO-568] Debug-support output for $search

Repository: olingo-odata4
Updated Branches:
  refs/heads/master ee3501dd8 -> 233ea61f3


[OLINGO-568] Debug-support output for $search

Signed-off-by: Christian Amend <ch...@sap.com>


Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/233ea61f
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/233ea61f
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/233ea61f

Branch: refs/heads/master
Commit: 233ea61f3ba6cdaf1cd7891695b045b799fb7a58
Parents: ee3501d
Author: Klaus Straubinger <kl...@sap.com>
Authored: Thu Nov 19 15:16:02 2015 +0100
Committer: Christian Amend <ch...@sap.com>
Committed: Thu Nov 19 15:44:58 2015 +0100

----------------------------------------------------------------------
 .../core/debug/DebugResponseHelperImpl.java     |  36 +-
 .../olingo/server/core/debug/DebugTabBody.java  |  22 +-
 .../olingo/server/core/debug/DebugTabUri.java   | 103 ++++--
 .../core/debug/ExpressionJsonVisitor.java       | 337 +++++++------------
 .../server/core/debug/JsonStreamWriter.java     | 175 ----------
 5 files changed, 211 insertions(+), 462 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/233ea61f/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugResponseHelperImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugResponseHelperImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugResponseHelperImpl.java
index 4cc17e6..3fc797b 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugResponseHelperImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugResponseHelperImpl.java
@@ -29,7 +29,6 @@ import java.util.Date;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
-import java.util.Map.Entry;
 
 import org.apache.olingo.commons.api.ex.ODataRuntimeException;
 import org.apache.olingo.commons.api.format.ContentType;
@@ -42,9 +41,8 @@ import org.apache.olingo.server.api.debug.DebugSupport;
 import org.apache.olingo.server.api.debug.RuntimeMeasurement;
 import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer;
 
-import com.fasterxml.jackson.core.JsonEncoding;
-import com.fasterxml.jackson.core.JsonFactory;
 import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.ObjectMapper;
 
 public class DebugResponseHelperImpl implements DebugResponseHelper {
 
@@ -141,7 +139,8 @@ public class DebugResponseHelperImpl implements DebugResponseHelper {
     try {
       CircleStreamBuffer csb = new CircleStreamBuffer();
       outputStream = csb.getOutputStream();
-      JsonGenerator gen = new JsonFactory().createGenerator(outputStream, JsonEncoding.UTF8);
+      // Create JSON generator (the object mapper is necessary to write expression trees).
+      JsonGenerator gen = new ObjectMapper().getFactory().createGenerator(outputStream);
 
       gen.writeStartObject();
       DebugTab requestInfo = parts.get(0);
@@ -232,11 +231,8 @@ public class DebugResponseHelperImpl implements DebugResponseHelper {
         .append("tbody > tr:hover { background-color: #cccccc; }\n")
         .append(".code { font-family: \"Courier New\", monospace; }\n")
         .append(".code, .tree li { line-height: 15px; }\n")
-        .append(".code a { text-decoration: underline; color: #666666; }\n")
-        .append(".xml .ns { font-style: italic; color: #999999; }\n")
-        .append("ul, .tree { list-style-type: none; }\n")
-        .append("div > ul.expr, div > .expand, .tree { padding-left: 0; }\n")
-        .append(".expr, .expand, .null, .numeric { padding-left: 1.5em; }\n")
+        .append("ul, .tree { padding-left: 0; list-style-type: none; }\n")
+        .append(".null, .numeric { padding-left: 1.5em; }\n")
         .append(".json { white-space: pre-wrap; }\n")
         .append("</style>\n")
         .append("</head>\n")
@@ -269,12 +265,12 @@ public class DebugResponseHelperImpl implements DebugResponseHelper {
       gen.writeNull();
     } else {
       gen.writeStartObject();
-      for (Map.Entry<String, String> entry : entries.entrySet()) {
-        gen.writeFieldName(entry.getKey());
-        if (entry.getValue() == null) {
+      for (final String name : entries.keySet()) {
+        gen.writeFieldName(name);
+        if (entries.get(name) == null) {
           gen.writeNull();
         } else {
-          gen.writeString(entry.getValue());
+          gen.writeString(entries.get(name));
         }
       }
       gen.writeEndObject();
@@ -286,15 +282,11 @@ public class DebugResponseHelperImpl implements DebugResponseHelper {
         .append("<tr><th class=\"name\">Name</th><th class=\"value\">Value</th></tr>\n")
         .append("</thead>\n<tbody>\n");
     if (entries != null && !entries.isEmpty()) {
-      for (final Entry<String, String> entry : entries.entrySet()) {
-        writer.append("<tr><td class=\"name\">").append(entry.getKey()).append("</td>")
-            .append("<td class=\"value\">");
-        if (entry.getValue() != null) {
-          writer.append(escapeHtml(entry.getValue()));
-        } else {
-          writer.append("null");
-        }
-        writer.append("</td></tr>\n");
+      for (final String name : entries.keySet()) {
+        writer.append("<tr><td class=\"name\">").append(name).append("</td>")
+            .append("<td class=\"value\">")
+            .append(escapeHtml(entries.get(name)))
+            .append("</td></tr>\n");
       }
     }
     writer.append("</tbody>\n</table>\n");

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/233ea61f/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabBody.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabBody.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabBody.java
index d290fc3..c75b6f6 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabBody.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabBody.java
@@ -18,19 +18,16 @@
  */
 package org.apache.olingo.server.core.debug;
 
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.Writer;
-import java.nio.ByteBuffer;
-import java.nio.channels.Channels;
-import java.nio.channels.ReadableByteChannel;
-import java.nio.channels.WritableByteChannel;
 
 import org.apache.commons.codec.binary.Base64;
 import org.apache.olingo.commons.api.ex.ODataRuntimeException;
 import org.apache.olingo.commons.api.http.HttpHeader;
 import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.deserializer.DeserializerException;
+import org.apache.olingo.server.core.deserializer.FixedFormatDeserializerImpl;
 
 import com.fasterxml.jackson.core.JsonGenerator;
 
@@ -134,20 +131,11 @@ public class DebugTabBody implements DebugTab {
   }
 
   private byte[] streamToBytes(InputStream input) {
-    ByteArrayOutputStream buffer = new ByteArrayOutputStream();
     if (input != null) {
       try {
-        ByteBuffer inBuffer = ByteBuffer.allocate(8192);
-        ReadableByteChannel ic = Channels.newChannel(input);
-        WritableByteChannel oc = Channels.newChannel(buffer);
-        while (ic.read(inBuffer) > 0) {
-          inBuffer.flip();
-          oc.write(inBuffer);
-          inBuffer.rewind();
-        }
-        return buffer.toByteArray();
-      } catch (IOException e) {
-        throw new ODataRuntimeException("Error on reading request content");
+        return new FixedFormatDeserializerImpl().binary(input);
+      } catch (final DeserializerException e) {
+        throw new ODataRuntimeException("Error on reading request content", e);
       }
     }
     return null;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/233ea61f/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabUri.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabUri.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabUri.java
index 66c755a..d36221d 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabUri.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabUri.java
@@ -39,15 +39,18 @@ import org.apache.olingo.server.api.uri.queryoption.FilterOption;
 import org.apache.olingo.server.api.uri.queryoption.OrderByItem;
 import org.apache.olingo.server.api.uri.queryoption.OrderByOption;
 import org.apache.olingo.server.api.uri.queryoption.QueryOption;
+import org.apache.olingo.server.api.uri.queryoption.SearchOption;
 import org.apache.olingo.server.api.uri.queryoption.SelectItem;
 import org.apache.olingo.server.api.uri.queryoption.SelectOption;
 import org.apache.olingo.server.api.uri.queryoption.SkipOption;
 import org.apache.olingo.server.api.uri.queryoption.TopOption;
 import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
+import org.apache.olingo.server.api.uri.queryoption.search.SearchExpression;
 
 import com.fasterxml.jackson.core.JsonFactory;
 import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
 
 /**
  * URI parser debug information.
@@ -87,7 +90,8 @@ public class DebugTabUri implements DebugTab {
     }
 
     appendCommonJsonObjects(gen, uriInfo.getCountOption(), uriInfo.getSkipOption(), uriInfo.getTopOption(),
-        uriInfo.getFilterOption(), uriInfo.getOrderByOption(), uriInfo.getSelectOption(), uriInfo.getExpandOption());
+        uriInfo.getFilterOption(), uriInfo.getOrderByOption(), uriInfo.getSelectOption(), uriInfo.getExpandOption(),
+        uriInfo.getSearchOption());
 
     if (!uriInfo.getAliases().isEmpty()) {
       gen.writeFieldName("aliases");
@@ -104,7 +108,7 @@ public class DebugTabUri implements DebugTab {
 
   private void appendCommonJsonObjects(JsonGenerator gen, CountOption countOption, SkipOption skipOption,
       TopOption topOption, FilterOption filterOption, OrderByOption orderByOption, SelectOption selectOption,
-      ExpandOption expandOption)
+      ExpandOption expandOption, SearchOption searchOption)
       throws IOException {
     if (countOption != null) {
       gen.writeBooleanField("isCount", countOption.getValue());
@@ -120,7 +124,7 @@ public class DebugTabUri implements DebugTab {
 
     if (filterOption != null) {
       gen.writeFieldName("filter");
-      appendJsonExpressionString(gen, filterOption.getExpression());
+      appendExpressionJson(gen, filterOption.getExpression());
     }
 
     if (orderByOption != null && !orderByOption.getOrders().isEmpty()) {
@@ -141,6 +145,11 @@ public class DebugTabUri implements DebugTab {
       gen.writeFieldName("expand");
       appendExpandedPropertiesJson(gen, expandOption.getExpandItems());
     }
+
+    if (searchOption != null) {
+      gen.writeFieldName("search");
+      appendSearchJson(gen, searchOption.getSearchExpression());
+    }
   }
 
   private void appendURIResourceParts(JsonGenerator gen, List<UriResource> uriResourceParts) throws IOException {
@@ -182,7 +191,7 @@ public class DebugTabUri implements DebugTab {
       gen.writeStringField("nodeType", "order");
       gen.writeStringField("sortorder", item.isDescending() ? "desc" : "asc");
       gen.writeFieldName("expression");
-      appendJsonExpressionString(gen, item.getExpression());
+      appendExpressionJson(gen, item.getExpression());
       gen.writeEndObject();
     }
     gen.writeEndArray();
@@ -221,24 +230,24 @@ public class DebugTabUri implements DebugTab {
       gen.writeNumberField("levels", item.getLevelsOption().getValue());
     }
 
-    appendCommonJsonObjects(gen, item.getCountOption(), item.getSkipOption(), item.getTopOption(), item
-        .getFilterOption(), item.getOrderByOption(), item.getSelectOption(), item.getExpandOption());
+    appendCommonJsonObjects(gen, item.getCountOption(), item.getSkipOption(), item.getTopOption(),
+        item.getFilterOption(), item.getOrderByOption(), item.getSelectOption(), item.getExpandOption(),
+        item.getSearchOption());
 
     gen.writeEndObject();
   }
 
-  private void appendJsonExpressionString(JsonGenerator gen, Expression expression) throws IOException {
+  private void appendExpressionJson(JsonGenerator gen, final Expression expression) throws IOException {
     if (expression == null) {
       gen.writeNull();
-      return;
-    }
-    String expressionJsonString;
-    try {
-      expressionJsonString = expression.accept(new ExpressionJsonVisitor());
-    } catch (final ODataException e) {
-      expressionJsonString = "Exception in Debug Filter visitor occurred: " + e.getMessage();
+    } else {
+      try {
+        final JsonNode tree = expression.accept(new ExpressionJsonVisitor());
+        gen.writeTree(tree);
+      } catch (final ODataException e) {
+        gen.writeString("Exception in Debug Expression visitor occurred: " + e.getMessage());
+      }
     }
-    gen.writeRawValue(expressionJsonString);
   }
 
   private void appendSelectedPropertiesJson(JsonGenerator gen, List<SelectItem> selectItems) throws IOException {
@@ -270,28 +279,61 @@ public class DebugTabUri implements DebugTab {
     return selectedProperty;
   }
 
+  private void appendSearchJson(JsonGenerator json, final SearchExpression searchExpression) throws IOException {
+    json.writeStartObject();
+    if (searchExpression.isSearchTerm()) {
+      json.writeStringField("nodeType", "searchTerm");
+      json.writeStringField("searchTerm", searchExpression.asSearchTerm().getSearchTerm());
+    } else if (searchExpression.isSearchBinary()) {
+      json.writeStringField("nodeType", "binary");
+      json.writeStringField("operator", searchExpression.asSearchBinary().getOperator().toString());
+      json.writeFieldName("left");
+      appendSearchJson(json, searchExpression.asSearchBinary().getLeftOperand());
+      json.writeFieldName("right");
+      appendSearchJson(json, searchExpression.asSearchBinary().getRightOperand());
+    } else if (searchExpression.isSearchUnary()) {
+      json.writeStringField("nodeType", "unary");
+      json.writeStringField("operator", searchExpression.asSearchUnary().getOperator().toString());
+      json.writeFieldName("operand");
+      appendSearchJson(json, searchExpression.asSearchUnary().getOperand());
+    }
+    json.writeEndObject();
+  }
+
   @Override
   public void appendHtml(final Writer writer) throws IOException {
+    // factory for JSON generators (the object mapper is necessary to write expression trees)
+    final JsonFactory jsonFactory = new ObjectMapper().getFactory();
+
     writer.append("<h2>Resource Path</h2>\n")
-        .append("<ul class=\"json\">\n<li>\n");
-    JsonGenerator json = new JsonFactory().createGenerator(writer).setPrettyPrinter(new DefaultPrettyPrinter());
+        .append("<ul>\n<li class=\"json\">");
+    JsonGenerator json = jsonFactory.createGenerator(writer).useDefaultPrettyPrinter();
     appendURIResourceParts(json, uriInfo.getUriResourceParts());
     json.close();
     writer.append("\n</li>\n</ul>\n");
 
+    if (uriInfo.getSearchOption() != null) {
+      writer.append("<h2>Search Option</h2>\n")
+          .append("<ul>\n<li class=\"json\">");
+      json = jsonFactory.createGenerator(writer).useDefaultPrettyPrinter();
+      appendSearchJson(json, uriInfo.getSearchOption().getSearchExpression());
+      json.close();
+      writer.append("\n</li>\n</ul>\n");
+    }
+
     if (uriInfo.getFilterOption() != null) {
       writer.append("<h2>Filter Option</h2>\n")
-          .append("<ul class=\"json\">\n<li>\n");
-      json = new JsonFactory().createGenerator(writer);
-      appendJsonExpressionString(json, uriInfo.getFilterOption().getExpression());
+          .append("<ul>\n<li class=\"json\">");
+      json = jsonFactory.createGenerator(writer).useDefaultPrettyPrinter();
+      appendExpressionJson(json, uriInfo.getFilterOption().getExpression());
       json.close();
       writer.append("\n</li>\n</ul>\n");
     }
 
     if (uriInfo.getOrderByOption() != null) {
       writer.append("<h2>OrderBy Option</h2>\n")
-          .append("<ul class=\"json\">\n<li>\n");
-      json = new JsonFactory().createGenerator(writer);
+          .append("<ul>\n<li class=\"json\">");
+      json = jsonFactory.createGenerator(writer).useDefaultPrettyPrinter();
       appendOrderByItemsJson(json, uriInfo.getOrderByOption().getOrders());
       json.close();
       writer.append("\n</li>\n</ul>\n");
@@ -299,8 +341,8 @@ public class DebugTabUri implements DebugTab {
 
     if (uriInfo.getExpandOption() != null) {
       writer.append("<h2>Expand Option</h2>\n")
-          .append("<ul class=\"json\">\n<li>\n");
-      json = new JsonFactory().createGenerator(writer);
+          .append("<ul>\n<li class=\"json\">");
+      json = jsonFactory.createGenerator(writer).useDefaultPrettyPrinter();
       appendExpandedPropertiesJson(json, uriInfo.getExpandOption().getExpandItems());
       json.close();
       writer.append("\n</li>\n</ul>\n");
@@ -315,23 +357,18 @@ public class DebugTabUri implements DebugTab {
       writer.append("</ul>\n");
     }
 
-    if (uriInfo.getSearchOption() != null) {
-      writer.append("<h2>Search Option</h2>\n")
-          .append("<p>not yet shown here</p>\n");
-    }
-
-    if (uriInfo.getSkipOption() != null
+    if (uriInfo.getCountOption() != null
+        || uriInfo.getSkipOption() != null
         || uriInfo.getSkipTokenOption() != null
         || uriInfo.getTopOption() != null
-        || uriInfo.getCountOption() != null
         || uriInfo.getFormatOption() != null
         || uriInfo.getIdOption() != null) {
       writer.append("<h2>Unstructured System Query Options</h2>\n");
       DebugResponseHelperImpl.appendHtmlTable(writer, getQueryOptionsMap(Arrays.asList(
+          uriInfo.getCountOption(),
           uriInfo.getSkipOption(),
           uriInfo.getSkipTokenOption(),
           uriInfo.getTopOption(),
-          uriInfo.getCountOption(),
           uriInfo.getFormatOption(),
           uriInfo.getIdOption())));
     }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/233ea61f/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/ExpressionJsonVisitor.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/ExpressionJsonVisitor.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/ExpressionJsonVisitor.java
index b09a991..5b8ebc8 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/ExpressionJsonVisitor.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/ExpressionJsonVisitor.java
@@ -18,8 +18,6 @@
  */
 package org.apache.olingo.server.core.debug;
 
-import java.io.IOException;
-import java.io.StringWriter;
 import java.util.List;
 
 import org.apache.olingo.commons.api.edm.EdmEnumType;
@@ -38,21 +36,25 @@ import org.apache.olingo.server.api.uri.queryoption.expression.Literal;
 import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
 import org.apache.olingo.server.api.uri.queryoption.expression.UnaryOperatorKind;
 
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
 /**
- * A custom expression visitor which writes down the tree from top to bottom
+ * A custom expression visitor which converts the tree into a {@link JsonNode} tree.
  */
-public class ExpressionJsonVisitor implements ExpressionVisitor<String> {
+public class ExpressionJsonVisitor implements ExpressionVisitor<JsonNode> {
 
   private static final String ANY_NAME = "ANY";
   private static final String ALL_NAME = "ALL";
-  private static final String STRING_NAME = "String";
   private static final String UNKNOWN_NAME = "unknown";
+  private static final String STRING_NAME = "String";
   private static final String BOOLEAN_NAME = "Boolean";
   private static final String NUMBER_NAME = "Number";
   private static final String ENUM_NAME = "enum";
   private static final String VALUES_NAME = "values";
   private static final String NAME_NAME = "name";
-  private static final String LAMBDA_REFERENCE_NAME = "lambdaReference";
   private static final String ALIAS_NAME = "alias";
   private static final String RESOURCE_SEGMENTS_NAME = "resourceSegments";
   private static final String MEMBER_NAME = "member";
@@ -61,11 +63,11 @@ public class ExpressionJsonVisitor implements ExpressionVisitor<String> {
   private static final String EXPRESSION_NAME = "expression";
   private static final String LAMBDA_VARIABLE_NAME = "lambdaVariable";
   private static final String LAMBDA_FUNCTION_NAME = "lambdaFunction";
+  private static final String LAMBDA_REFERENCE_NAME = "lambdaReference";
   private static final String UNARY_NAME = "unary";
   private static final String BINARY_NAME = "binary";
   private static final String LEFT_NODE_NAME = "left";
   private static final String RIGHT_NODE_NAME = "right";
-  private static final String IO_EXCEPTION_OCCURRED_MESSAGE = "IOException occurred";
   private static final String PARAMETERS_NAME = "parameters";
   private static final String METHOD_NAME = "method";
   private static final String OPERAND_NAME = "operand";
@@ -73,203 +75,133 @@ public class ExpressionJsonVisitor implements ExpressionVisitor<String> {
   private static final String OPERATOR_NAME = "operator";
   private static final String NODE_TYPE_NAME = "nodeType";
 
+  private final JsonNodeFactory nodeFactory = JsonNodeFactory.instance;
+
   @Override
-  public String visitBinaryOperator(BinaryOperatorKind operator, String left, String right)
+  public JsonNode visitBinaryOperator(final BinaryOperatorKind operator, final JsonNode left, final JsonNode right)
       throws ExpressionVisitException, ODataApplicationException {
-    try {
-      StringWriter writer = new StringWriter();
-      JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
-      jsonStreamWriter.beginObject().namedStringValue(NODE_TYPE_NAME, BINARY_NAME).separator().namedStringValue(
-          OPERATOR_NAME, operator.toString()).separator().namedStringValueRaw(TYPE_NAME, getType(operator)).separator()
-          .name(LEFT_NODE_NAME).unquotedValue(left).separator().name(RIGHT_NODE_NAME).unquotedValue(right).endObject();
-      writer.flush();
-      return writer.toString();
-    } catch (final IOException e) {
-      throw new ExpressionVisitException(IO_EXCEPTION_OCCURRED_MESSAGE, e);
-    }
+    ObjectNode result = nodeFactory.objectNode()
+        .put(NODE_TYPE_NAME, BINARY_NAME)
+        .put(OPERATOR_NAME, operator.toString())
+        .put(TYPE_NAME, getType(operator));
+    result.set(LEFT_NODE_NAME, left);
+    result.set(RIGHT_NODE_NAME, right);
+    return result;
   }
 
   @Override
-  public String visitUnaryOperator(UnaryOperatorKind operator, String operand) throws ExpressionVisitException,
-      ODataApplicationException {
-    try {
-      StringWriter writer = new StringWriter();
-      JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
-      jsonStreamWriter.beginObject().namedStringValue(NODE_TYPE_NAME, UNARY_NAME).separator()
-          .namedStringValueRaw(OPERATOR_NAME, operator.toString()).separator().namedStringValueRaw(TYPE_NAME,
-              getType(operator)).separator().name(OPERAND_NAME).unquotedValue(operand).endObject();
-      writer.flush();
-      return writer.toString();
-    } catch (final IOException e) {
-      throw new ExpressionVisitException(IO_EXCEPTION_OCCURRED_MESSAGE, e);
-    }
+  public JsonNode visitUnaryOperator(final UnaryOperatorKind operator, final JsonNode operand)
+      throws ExpressionVisitException, ODataApplicationException {
+    return nodeFactory.objectNode()
+        .put(NODE_TYPE_NAME, UNARY_NAME)
+        .put(OPERATOR_NAME, operator.toString())
+        .put(TYPE_NAME, getType(operator))
+        .set(OPERAND_NAME, operand);
   }
 
   @Override
-  public String visitMethodCall(MethodKind methodCall, List<String> parameters) throws ExpressionVisitException,
-      ODataApplicationException {
-    try {
-      StringWriter writer = new StringWriter();
-      JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
-      jsonStreamWriter.beginObject().namedStringValueRaw(NODE_TYPE_NAME, METHOD_NAME).separator()
-          .namedStringValueRaw(OPERATOR_NAME, methodCall.toString()).separator().namedStringValueRaw(TYPE_NAME,
-              getType(methodCall)).separator().name(PARAMETERS_NAME).beginArray();
-      boolean first = true;
-      for (String parameter : parameters) {
-        if (first) {
-          first = false;
-        } else {
-          jsonStreamWriter.separator();
-        }
-        jsonStreamWriter.unquotedValue(parameter);
-      }
-      jsonStreamWriter.endArray().endObject();
-      writer.flush();
-      return writer.toString();
-    } catch (final IOException e) {
-      throw new ExpressionVisitException(IO_EXCEPTION_OCCURRED_MESSAGE, e);
+  public JsonNode visitMethodCall(final MethodKind methodCall, final List<JsonNode> parameters)
+      throws ExpressionVisitException, ODataApplicationException {
+    ObjectNode result = nodeFactory.objectNode()
+        .put(NODE_TYPE_NAME, METHOD_NAME)
+        .put(OPERATOR_NAME, methodCall.toString())
+        .put(TYPE_NAME, getType(methodCall));
+    ArrayNode jsonParameters = result.putArray(PARAMETERS_NAME);
+    for (final JsonNode parameter : parameters) {
+      jsonParameters.add(parameter);
     }
+    return result;
   }
 
   @Override
-  public String visitLambdaExpression(String lambdaFunction, String lambdaVariable, Expression expression)
-      throws ExpressionVisitException, ODataApplicationException {
-    try {
-      StringWriter writer = new StringWriter();
-      JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
-      jsonStreamWriter.beginObject().namedStringValue(NODE_TYPE_NAME, LAMBDA_FUNCTION_NAME).separator()
-          .namedStringValue(LAMBDA_VARIABLE_NAME, lambdaVariable).separator().name(EXPRESSION_NAME);
-
-      // Write expression string object
-      String expressionJsonTree = expression.accept(this);
-      jsonStreamWriter.unquotedValue(expressionJsonTree).endObject();
-      writer.flush();
-      return writer.toString();
-    } catch (final IOException e) {
-      throw new ExpressionVisitException(IO_EXCEPTION_OCCURRED_MESSAGE, e);
-    }
+  public JsonNode visitLambdaExpression(final String lambdaFunction, final String lambdaVariable,
+      final Expression expression) throws ExpressionVisitException, ODataApplicationException {
+    return nodeFactory.objectNode()
+        .put(NODE_TYPE_NAME, LAMBDA_FUNCTION_NAME)
+        .put(LAMBDA_VARIABLE_NAME, lambdaVariable)
+        .set(EXPRESSION_NAME, expression.accept(this));
   }
 
   @Override
-  public String visitLiteral(Literal literal) throws ExpressionVisitException, ODataApplicationException {
-    try {
-      StringWriter writer = new StringWriter();
-      JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
-      jsonStreamWriter.beginObject().namedStringValueRaw(NODE_TYPE_NAME, LITERAL_NAME).separator().namedStringValueRaw(
-          TYPE_NAME, getTypeString(literal.getType())).separator().namedStringValue(VALUE_NAME, literal.getText())
-          .endObject();
-      writer.flush();
-      return writer.toString();
-    } catch (final IOException e) {
-      throw new ExpressionVisitException(IO_EXCEPTION_OCCURRED_MESSAGE);
-    }
+  public JsonNode visitLiteral(final Literal literal) throws ExpressionVisitException, ODataApplicationException {
+    return nodeFactory.objectNode()
+        .put(NODE_TYPE_NAME, LITERAL_NAME)
+        .put(TYPE_NAME, getTypeString(literal.getType()))
+        .put(VALUE_NAME, literal.getText());
   }
 
   @Override
-  public String visitMember(UriInfoResource member) throws ExpressionVisitException, ODataApplicationException {
-    try {
-      StringWriter writer = new StringWriter();
-      JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
-      List<UriResource> uriResourceParts = member.getUriResourceParts();
-      jsonStreamWriter.beginObject().namedStringValue(NODE_TYPE_NAME, MEMBER_NAME).separator()
-          .namedStringValueRaw(TYPE_NAME, getType(uriResourceParts)).separator();
-
-      // write all member properties in an array
-      jsonStreamWriter.name(RESOURCE_SEGMENTS_NAME).beginArray();
-      if (uriResourceParts != null) {
-        boolean first = true;
-        for (UriResource segment : uriResourceParts) {
-          if (first) {
-            first = false;
-          } else {
-            jsonStreamWriter.separator();
-          }
-          appendUriResourcePartObject(jsonStreamWriter, segment);
+  public JsonNode visitMember(final UriInfoResource member)
+      throws ExpressionVisitException, ODataApplicationException {
+    final List<UriResource> uriResourceParts = member.getUriResourceParts();
+    ObjectNode result = nodeFactory.objectNode()
+        .put(NODE_TYPE_NAME, MEMBER_NAME)
+        .put(TYPE_NAME, getType(uriResourceParts));
+    ArrayNode segments = result.putArray(RESOURCE_SEGMENTS_NAME);
+    if (uriResourceParts != null) {
+      for (final UriResource segment : uriResourceParts) {
+        if (segment instanceof UriResourceLambdaAll) {
+          final UriResourceLambdaAll all = (UriResourceLambdaAll) segment;
+          segments.add(visitLambdaExpression(ALL_NAME, all.getLambdaVariable(), all.getExpression()));
+        } else if (segment instanceof UriResourceLambdaAny) {
+          final UriResourceLambdaAny any = (UriResourceLambdaAny) segment;
+          segments.add(visitLambdaExpression(ANY_NAME, any.getLambdaVariable(), any.getExpression()));
+        } else if (segment instanceof UriResourcePartTyped) {
+          final String typeName = ((UriResourcePartTyped) segment).getType()
+              .getFullQualifiedName().getFullQualifiedNameAsString();
+          segments.add(nodeFactory.objectNode()
+              .put(NODE_TYPE_NAME, segment.getKind().toString())
+              .put(NAME_NAME, segment.toString())
+              .put(TYPE_NAME, typeName));
+        } else {
+          segments.add(nodeFactory.objectNode()
+              .put(NODE_TYPE_NAME, segment.getKind().toString())
+              .put(NAME_NAME, segment.toString())
+              .putNull(TYPE_NAME));
         }
       }
-      jsonStreamWriter.endArray();
-
-      jsonStreamWriter.endObject();
-      writer.flush();
-      return writer.toString();
-    } catch (final IOException e) {
-      throw new ExpressionVisitException(IO_EXCEPTION_OCCURRED_MESSAGE, e);
     }
+    return result;
   }
 
   @Override
-  public String visitAlias(String aliasName) throws ExpressionVisitException, ODataApplicationException {
-    try {
-      StringWriter writer = new StringWriter();
-      JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
-      jsonStreamWriter.beginObject().namedStringValueRaw(NODE_TYPE_NAME, ALIAS_NAME).separator()
-          .namedStringValue(ALIAS_NAME, aliasName).endObject();
-      writer.flush();
-      return writer.toString();
-    } catch (final IOException e) {
-      throw new ExpressionVisitException(IO_EXCEPTION_OCCURRED_MESSAGE, e);
-    }
+  public JsonNode visitAlias(final String aliasName) throws ExpressionVisitException, ODataApplicationException {
+    return nodeFactory.objectNode()
+        .put(NODE_TYPE_NAME, ALIAS_NAME)
+        .put(ALIAS_NAME, aliasName);
   }
 
   @Override
-  public String visitTypeLiteral(EdmType type) throws ExpressionVisitException, ODataApplicationException {
-    try {
-      StringWriter writer = new StringWriter();
-      JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
-      jsonStreamWriter.beginObject().namedStringValueRaw(NODE_TYPE_NAME, TYPE_NAME).separator()
-          .namedStringValueRaw(TYPE_NAME, getTypeString(type)).endObject();
-      writer.flush();
-      return writer.toString();
-    } catch (final IOException e) {
-      throw new ExpressionVisitException(IO_EXCEPTION_OCCURRED_MESSAGE, e);
-    }
+  public JsonNode visitTypeLiteral(final EdmType type) throws ExpressionVisitException, ODataApplicationException {
+    return nodeFactory.objectNode()
+        .put(NODE_TYPE_NAME, TYPE_NAME)
+        .put(TYPE_NAME, getTypeString(type));
   }
 
   @Override
-  public String visitLambdaReference(String variableName) throws ExpressionVisitException, ODataApplicationException {
-    try {
-      StringWriter writer = new StringWriter();
-      JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
-      jsonStreamWriter.beginObject().namedStringValueRaw(NODE_TYPE_NAME, LAMBDA_REFERENCE_NAME).separator()
-          .namedStringValueRaw(NAME_NAME, variableName).endObject();
-      writer.flush();
-      return writer.toString();
-    } catch (final IOException e) {
-      throw new ExpressionVisitException(IO_EXCEPTION_OCCURRED_MESSAGE, e);
-    }
+  public JsonNode visitLambdaReference(final String variableName)
+      throws ExpressionVisitException, ODataApplicationException {
+    return nodeFactory.objectNode()
+        .put(NODE_TYPE_NAME, LAMBDA_REFERENCE_NAME)
+        .put(NAME_NAME, variableName);
   }
 
   @Override
-  public String visitEnum(EdmEnumType type, List<String> enumValues) throws ExpressionVisitException,
+  public JsonNode visitEnum(final EdmEnumType type, final List<String> enumValues) throws ExpressionVisitException,
       ODataApplicationException {
-    try {
-      StringWriter writer = new StringWriter();
-      JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
-      jsonStreamWriter.beginObject().namedStringValueRaw(NODE_TYPE_NAME, ENUM_NAME).separator()
-          .namedStringValueRaw(TYPE_NAME, getTypeString(type)).separator();
-      jsonStreamWriter.name(VALUES_NAME).beginArray();
-      if (enumValues != null) {
-        boolean first = true;
-        for (String value : enumValues) {
-          if (first) {
-            first = false;
-          } else {
-            jsonStreamWriter.separator();
-          }
-          jsonStreamWriter.stringValue(value);
-        }
+    ObjectNode result = nodeFactory.objectNode()
+        .put(NODE_TYPE_NAME, ENUM_NAME)
+        .put(TYPE_NAME, getTypeString(type));
+    ArrayNode values = result.putArray(VALUES_NAME);
+    if (enumValues != null) {
+      for (final String enumValue : enumValues) {
+        values.add(enumValue);
       }
-      jsonStreamWriter.endArray();
-
-      jsonStreamWriter.endObject();
-      writer.flush();
-      return writer.toString();
-    } catch (final IOException e) {
-      throw new ExpressionVisitException(IO_EXCEPTION_OCCURRED_MESSAGE, e);
     }
+    return result;
   }
 
-  private String getType(UnaryOperatorKind operator) {
+  private String getType(final UnaryOperatorKind operator) {
     switch (operator) {
     case MINUS:
       return NUMBER_NAME;
@@ -280,72 +212,51 @@ public class ExpressionJsonVisitor implements ExpressionVisitor<String> {
     }
   }
 
-  private String getType(MethodKind methodCall) {
+  private String getType(final MethodKind methodCall) {
     switch (methodCall) {
     case STARTSWITH:
     case CONTAINS:
     case ENDSWITH:
     case ISOF:
+    case GEOINTERSECTS:
       return BOOLEAN_NAME;
+
     case INDEXOF:
     case LENGTH:
     case ROUND:
     case FLOOR:
     case CEILING:
+    case YEAR:
+    case MONTH:
     case DAY:
     case HOUR:
     case MINUTE:
-    case MONTH:
     case SECOND:
     case FRACTIONALSECONDS:
+    case TOTALOFFSETMINUTES:
+    case TOTALSECONDS:
       return NUMBER_NAME;
-    case CAST:
+
     case CONCAT:
-    case DATE:
-    case GEODISTANCE:
-    case GEOINTERSECTS:
-    case GEOLENGTH:
-    case MAXDATETIME:
-    case MINDATETIME:
-    case NOW:
     case SUBSTRING:
-    case TIME:
     case TOLOWER:
-    case TOTALOFFSETMINUTES:
-    case TOTALSECONDS:
     case TOUPPER:
     case TRIM:
-    case YEAR:
       return STRING_NAME;
+
+    case CAST:
+    case GEODISTANCE:
+    case GEOLENGTH:
+    case MAXDATETIME:
+    case MINDATETIME:
+    case DATE:
+    case TIME:
+    case NOW:
     default:
       return UNKNOWN_NAME;
     }
   }
 
-  private void appendUriResourcePartObject(JsonStreamWriter jsonStreamWriter, UriResource segment) throws IOException,
-      ExpressionVisitException, ODataApplicationException {
-    if (segment instanceof UriResourceLambdaAll) {
-      UriResourceLambdaAll all = (UriResourceLambdaAll) segment;
-      String lambdaJsonObjectString = visitLambdaExpression(ALL_NAME, all.getLambdaVariable(), all.getExpression());
-      jsonStreamWriter.unquotedValue(lambdaJsonObjectString);
-      return;
-    } else if (segment instanceof UriResourceLambdaAny) {
-      UriResourceLambdaAny any = (UriResourceLambdaAny) segment;
-      String lambdaJsonObjectString = visitLambdaExpression(ANY_NAME, any.getLambdaVariable(), any.getExpression());
-      jsonStreamWriter.unquotedValue(lambdaJsonObjectString);
-      return;
-    } else if (segment instanceof UriResourcePartTyped) {
-      String typeName =
-          ((UriResourcePartTyped) segment).getType().getFullQualifiedName().getFullQualifiedNameAsString();
-      jsonStreamWriter.beginObject().namedStringValue(NODE_TYPE_NAME, segment.getKind().toString()).separator()
-          .namedStringValue(NAME_NAME, segment.toString()).separator().namedStringValueRaw(TYPE_NAME, typeName)
-          .endObject();
-    } else {
-      jsonStreamWriter.beginObject().namedStringValue(NODE_TYPE_NAME, segment.getKind().toString()).separator()
-          .namedStringValue(NAME_NAME, segment.toString()).separator().namedStringValueRaw(TYPE_NAME, null).endObject();
-    }
-  }
-
   private String getType(BinaryOperatorKind operator) {
     switch (operator) {
     case MUL:
@@ -371,22 +282,18 @@ public class ExpressionJsonVisitor implements ExpressionVisitor<String> {
     }
   }
 
-  private String getTypeString(EdmType type) {
-    if (type == null) {
-      return null;
-    }
-    return type.getFullQualifiedName().getFullQualifiedNameAsString();
+  private String getTypeString(final EdmType type) {
+    return type == null ? null : type.getFullQualifiedName().getFullQualifiedNameAsString();
   }
 
-  private String getType(List<UriResource> uriResourceParts) {
+  private String getType(final List<UriResource> uriResourceParts) {
     if (uriResourceParts == null || uriResourceParts.isEmpty()) {
       return null;
     }
-    UriResource lastSegment = uriResourceParts.get(uriResourceParts.size() - 1);
-    EdmType type = null;
-    if (lastSegment instanceof UriResourcePartTyped) {
-      type = ((UriResourcePartTyped) lastSegment).getType();
-    }
+    final UriResource lastSegment = uriResourceParts.get(uriResourceParts.size() - 1);
+    final EdmType type = lastSegment instanceof UriResourcePartTyped ?
+        ((UriResourcePartTyped) lastSegment).getType() :
+        null;
     return type == null ? UNKNOWN_NAME : type.getFullQualifiedName().getFullQualifiedNameAsString();
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/233ea61f/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/JsonStreamWriter.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/JsonStreamWriter.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/JsonStreamWriter.java
deleted file mode 100644
index 113b45d..0000000
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/JsonStreamWriter.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.olingo.server.core.debug;
-
-import java.io.IOException;
-import java.io.Writer;
-
-/**
- * Writes JSON output.
- * 
- */
-class JsonStreamWriter {
-  private final Writer writer;
-
-  public JsonStreamWriter(final Writer writer) {
-    this.writer = writer;
-  }
-
-  public JsonStreamWriter beginObject() throws IOException {
-    writer.append('{');
-    return this;
-  }
-
-  public JsonStreamWriter endObject() throws IOException {
-    writer.append('}');
-    return this;
-  }
-
-  public JsonStreamWriter beginArray() throws IOException {
-    writer.append('[');
-    return this;
-  }
-
-  public JsonStreamWriter endArray() throws IOException {
-    writer.append(']');
-    return this;
-  }
-
-  public JsonStreamWriter name(final String name) throws IOException {
-    writer.append('"').append(name).append('"').append(':');
-    return this;
-  }
-
-  public JsonStreamWriter unquotedValue(final String value) throws IOException {
-    writer.append(value == null ? "null" : value);
-    return this;
-  }
-
-  public JsonStreamWriter stringValueRaw(final String value) throws IOException {
-    if (value == null) {
-      writer.append("null");
-    } else {
-      writer.append('"').append(value).append('"');
-    }
-    return this;
-  }
-
-  public JsonStreamWriter stringValue(final String value) throws IOException {
-    if (value == null) {
-      writer.append("null");
-    } else {
-      writer.append('"');
-      escape(value);
-      writer.append('"');
-    }
-    return this;
-  }
-
-  public JsonStreamWriter namedStringValueRaw(final String name, final String value) throws IOException {
-    name(name);
-    stringValueRaw(value);
-    return this;
-  }
-
-  public JsonStreamWriter namedStringValue(final String name, final String value) throws IOException {
-    name(name);
-    stringValue(value);
-    return this;
-  }
-
-  public JsonStreamWriter separator() throws IOException {
-    writer.append(',');
-    return this;
-  }
-
-  /**
-   * Writes the JSON-escaped form of a Java String value according to RFC 4627.
-   * @param value the Java String
-   * @throws IOException if an I/O error occurs
-   */
-  protected void escape(final String value) throws IOException {
-    // RFC 4627 says: "All Unicode characters may be placed within the
-    // quotation marks except for the characters that must be escaped:
-    // quotation mark, reverse solidus, and the control characters
-    // (U+0000 through U+001F)."
-    // All output here is done on character basis which should be faster
-    // than writing Strings.
-    for (int i = 0; i < value.length(); i++) {
-      final char c = value.charAt(i);
-      switch (c) {
-      case '\\':
-        writer.append('\\').append(c);
-        break;
-      case '"':
-        writer.append('\\').append(c);
-        break;
-      case '\b':
-        writer.append('\\').append('b');
-        break;
-      case '\t':
-        writer.append('\\').append('t');
-        break;
-      case '\n':
-        writer.append('\\').append('n');
-        break;
-      case '\f':
-        writer.append('\\').append('f');
-        break;
-      case '\r':
-        writer.append('\\').append('r');
-        break;
-      case '\u0000':
-      case '\u0001':
-      case '\u0002':
-      case '\u0003':
-      case '\u0004':
-      case '\u0005':
-      case '\u0006':
-      case '\u0007':
-      case '\u000B':
-      case '\u000E':
-      case '\u000F':
-      case '\u0010':
-      case '\u0011':
-      case '\u0012':
-      case '\u0013':
-      case '\u0014':
-      case '\u0015':
-      case '\u0016':
-      case '\u0017':
-      case '\u0018':
-      case '\u0019':
-      case '\u001A':
-      case '\u001B':
-      case '\u001C':
-      case '\u001D':
-      case '\u001E':
-      case '\u001F':
-        final int lastHexDigit = c % 0x10;
-        writer.append('\\').append('u').append('0').append('0')
-            .append(c >= '\u0010' ? '1' : '0')
-            .append((char) ((lastHexDigit > 9 ? 'A' : '0') + lastHexDigit % 10));
-        break;
-      default:
-        writer.append(c);
-      }
-    }
-  }
-}