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/08/12 17:21:55 UTC

olingo-odata4 git commit: [Olingo-731] add json uri tab support

Repository: olingo-odata4
Updated Branches:
  refs/heads/olingo731 [created] 0ce9c45d6


[Olingo-731] add json uri tab support


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

Branch: refs/heads/olingo731
Commit: 0ce9c45d6c4a9fade931445ce94fed7cf449ac29
Parents: 2ca8e0d
Author: Christian Amend <ch...@sap.com>
Authored: Wed Aug 12 17:20:14 2015 +0200
Committer: Christian Amend <ch...@sap.com>
Committed: Wed Aug 12 17:21:18 2015 +0200

----------------------------------------------------------------------
 .../expression/ExpressionVisitor.java           |   2 +-
 .../core/debug/DebugResponseHelperImpl.java     |   8 +-
 .../olingo/server/core/debug/DebugTabUri.java   | 100 ++++-
 .../core/debug/ExpressionJsonVisitor.java       | 361 +++++++++++++++++++
 .../server/core/debug/JsonStreamWriter.java     | 175 +++++++++
 .../uri/queryoption/expression/LiteralImpl.java |   2 +-
 .../expression/ExpressionVisitorImpl.java       |   6 +-
 .../core/uri/testutil/FilterTreeToText.java     |   5 +-
 8 files changed, 641 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0ce9c45d/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/expression/ExpressionVisitor.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/expression/ExpressionVisitor.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/expression/ExpressionVisitor.java
index e2d4f94..f0ddce8 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/expression/ExpressionVisitor.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/expression/ExpressionVisitor.java
@@ -85,7 +85,7 @@ public interface ExpressionVisitor<T> {
    * @throws ExpressionVisitException Thrown if an exception while traversing occured
    * @throws ODataApplicationException Thrown by the application
    */
-  T visitLiteral(String literal) throws ExpressionVisitException, ODataApplicationException;
+  T visitLiteral(Literal literal) throws ExpressionVisitException, ODataApplicationException;
 
   /**
    * Called for each traversed {@link Member} expression

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0ce9c45d/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 4b093e9..e9512f2 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
@@ -113,12 +113,10 @@ public class DebugResponseHelperImpl implements DebugResponseHelper {
       parts.add(new DebugTabServer(serverEnvironmentVaribles));
     }
 
-    // TODO:Enable URIDebugInfo
     // URI
-//    if (uriInfo != null && (uriInfo.getFilterOption() != null || uriInfo.getOrderByOption() != null
-//        || uriInfo.getExpandOption() != null || uriInfo.getSelectOption() != null)) {
-//      parts.add(new DebugInfoUri(uriInfo));
-//    }
+    if (debugInfo.getUriInfo() != null ) {
+      parts.add(new DebugTabUri(debugInfo.getUriInfo()));
+    }
 
     // runtime measurements
     List<RuntimeMeasurement> runtimeInformation = debugInfo.getRuntimeInformation();

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0ce9c45d/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 5c50c0f..f1ee69c 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
@@ -20,21 +20,31 @@ package org.apache.olingo.server.core.debug;
 
 import java.io.IOException;
 import java.io.Writer;
+import java.util.List;
 
 import org.apache.olingo.server.api.uri.UriInfo;
+import org.apache.olingo.server.api.uri.UriResource;
+import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
+import org.apache.olingo.server.api.uri.queryoption.OrderByItem;
+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.expression.Expression;
 
 import com.fasterxml.jackson.core.JsonGenerator;
 
-
 /**
  * URI parser debug information.
  */
 public class DebugTabUri implements DebugTab {
 
-  private UriInfo uriInfo;
+  private final UriInfo uriInfo;
+  private final SelectOption selectOption;
+  private final ExpandOption expandOption;
 
   public DebugTabUri(UriInfo uriInfo) {
     this.uriInfo = uriInfo;
+    this.selectOption = uriInfo == null ? null : uriInfo.getSelectOption();
+    this.expandOption = uriInfo == null ? null : uriInfo.getExpandOption();
   }
 
   @Override
@@ -43,15 +53,93 @@ public class DebugTabUri implements DebugTab {
   }
 
   @Override
-  public void appendJson(JsonGenerator jsonGenerator) throws IOException {
-    // TODO Auto-generated method stub
-    
+  public void appendJson(JsonGenerator gen) throws IOException {
+    if (uriInfo == null) {
+      gen.writeNull();
+      return;
+    }
+
+    gen.writeStartObject();
+
+    if (uriInfo.getFilterOption() != null) {
+      gen.writeFieldName("filter");
+      appendJsonExpressionString(gen, uriInfo.getFilterOption().getExpression());
+    }
+
+    if (uriInfo.getOrderByOption() != null && uriInfo.getOrderByOption().getOrders() != null
+        && !uriInfo.getOrderByOption().getOrders().isEmpty()) {
+      gen.writeFieldName("orderby");
+      gen.writeStartObject();
+      gen.writeStringField("nodeType", "orderCollection");
+      gen.writeFieldName("orders");
+      gen.writeStartArray();
+      for(OrderByItem item : uriInfo.getOrderByOption().getOrders()){
+        gen.writeStartObject();
+        gen.writeStringField("nodeType", "order");
+        gen.writeStringField("sortorder", item.isDescending() ? "desc" : "asc");
+        gen.writeFieldName("expression");
+        appendJsonExpressionString(gen, item.getExpression());
+        gen.writeEndObject();
+      }
+      gen.writeEndArray();
+      gen.writeEndObject();
+    }
+
+    if (selectOption != null && !selectOption.getSelectItems().isEmpty()) {
+      appendSelectedPropertiesJson(gen, selectOption.getSelectItems());
+    }
+
+    gen.writeEndObject();
+  }
+
+  private void appendJsonExpressionString(JsonGenerator gen, Expression expression) throws IOException {
+    if(expression == null){
+      gen.writeNull();
+      return;
+    }
+    String expressionJsonString;
+    try {
+      expressionJsonString = expression.accept(new ExpressionJsonVisitor());
+    } catch (Exception e) {
+      expressionJsonString = "Exception in Debug Filter visitor occoured: " + e.getMessage();
+    }
+
+    gen.writeRawValue(expressionJsonString);
+  }
+
+  private void appendSelectedPropertiesJson(JsonGenerator gen, List<SelectItem> selectItems) throws IOException {
+    gen.writeFieldName("select");
+
+    gen.writeStartArray();
+    for (SelectItem selectItem : selectItems) {
+      appendSelectItemJson(gen, selectItem);
+    }
+    gen.writeEndArray();
+  }
+
+  private void appendSelectItemJson(JsonGenerator gen, SelectItem selectItem) throws IOException {
+    String selectedProperty = "";
+    if (selectItem.isStar()) {
+      if (selectItem.getAllOperationsInSchemaNameSpace() == null) {
+        selectedProperty = "*";
+      } else {
+        selectedProperty = selectItem.getAllOperationsInSchemaNameSpace().getFullQualifiedNameAsString() + ".*";
+      }
+    } else {
+      boolean first = true;
+      for (UriResource resourcePart : selectItem.getResourcePath().getUriResourceParts()) {
+        if (!first) {
+          selectedProperty = selectedProperty + "/";
+        }
+        selectedProperty = resourcePart.toString();
+      }
+    }
   }
 
   @Override
   public void appendHtml(Writer writer) throws IOException {
     // TODO Auto-generated method stub
-    
+
   }
 
 //  private final UriInfo uriInfo;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0ce9c45d/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
new file mode 100644
index 0000000..773ea48
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/ExpressionJsonVisitor.java
@@ -0,0 +1,361 @@
+/*
+ * 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.StringWriter;
+import java.util.List;
+
+import org.apache.olingo.commons.api.edm.EdmEnumType;
+import org.apache.olingo.commons.api.edm.EdmType;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.uri.UriInfoResource;
+import org.apache.olingo.server.api.uri.UriResource;
+import org.apache.olingo.server.api.uri.UriResourceLambdaAll;
+import org.apache.olingo.server.api.uri.UriResourceLambdaAny;
+import org.apache.olingo.server.api.uri.UriResourcePartTyped;
+import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
+import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
+import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException;
+import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitor;
+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;
+
+/**
+ * A custom expression visitor which writes down the tree from top to bottom
+ */
+public class ExpressionJsonVisitor implements ExpressionVisitor<String> {
+
+  @Override
+  public String visitBinaryOperator(BinaryOperatorKind operator, String left, String right)
+      throws ExpressionVisitException, ODataApplicationException {
+    try {
+      StringWriter writer = new StringWriter();
+      JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
+      jsonStreamWriter.beginObject().namedStringValue("nodeType", "binary").separator().namedStringValue("operator",
+          operator.toString()).separator().namedStringValueRaw("type", getType(operator)).separator().name("left")
+          .unquotedValue(left).separator().name("right").unquotedValue(right).endObject();
+      writer.flush();
+      return writer.toString();
+    } catch (final IOException e) {
+      throw new ExpressionVisitException("IOException occoured", e);
+    }
+  }
+
+  @Override
+  public String visitUnaryOperator(UnaryOperatorKind operator, String operand) throws ExpressionVisitException,
+      ODataApplicationException {
+    try {
+      StringWriter writer = new StringWriter();
+      JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
+      jsonStreamWriter.beginObject().namedStringValue("nodeType", "unary").separator()
+          .namedStringValueRaw("operator", operator.toString()).separator().namedStringValueRaw("type",
+              getType(operator)).separator().name("operand").unquotedValue(operand).endObject();
+      writer.flush();
+      return writer.toString();
+    } catch (final IOException e) {
+      throw new ExpressionVisitException("IOException occoured", e);
+    }
+  }
+
+  @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("nodeType", "method").separator()
+          .namedStringValueRaw("operator", methodCall.toString()).separator().namedStringValueRaw("type",
+              getType(methodCall)).separator().name("parameters").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("IOException occoured", e);
+    }
+  }
+
+  @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("nodeType", "lambdaFunction").separator()
+          .namedStringValue("lambdaVariable", lambdaVariable).separator().name("expression");
+
+      // 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("IOException occoured", e);
+    }
+  }
+
+  @Override
+  public String visitLiteral(Literal literal) throws ExpressionVisitException, ODataApplicationException {
+    try {
+      StringWriter writer = new StringWriter();
+      JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
+      jsonStreamWriter.beginObject().namedStringValueRaw("nodeType", "literal").separator().namedStringValueRaw("type",
+          getTypeString(literal.getType())).separator().namedStringValue("value", literal.getText()).endObject();
+      writer.flush();
+      return writer.toString();
+    } catch (final IOException e) {
+      throw new ExpressionVisitException("IOException occoured");
+    }
+  }
+
+  @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("nodeType", "member").separator()
+          .namedStringValueRaw("type", getType(uriResourceParts)).separator();
+
+      // write all member properties in an array
+      jsonStreamWriter.name("resourceSegments").beginArray();
+      if (uriResourceParts != null) {
+        boolean first = true;
+        for (UriResource segment : uriResourceParts) {
+          if (first) {
+            first = false;
+          } else {
+            jsonStreamWriter.separator();
+          }
+          appendUriResourcePartObject(jsonStreamWriter, segment);
+        }
+      }
+      jsonStreamWriter.endArray();
+
+      jsonStreamWriter.endObject();
+      writer.flush();
+      return writer.toString();
+    } catch (final IOException e) {
+      throw new ExpressionVisitException("IOException occoured", e);
+    }
+  }
+
+  @Override
+  public String visitAlias(String aliasName) throws ExpressionVisitException, ODataApplicationException {
+    try {
+      StringWriter writer = new StringWriter();
+      JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
+      jsonStreamWriter.beginObject().namedStringValueRaw("nodeType", "alias").separator()
+          .namedStringValue("alias", aliasName).endObject();
+      writer.flush();
+      return writer.toString();
+    } catch (final IOException e) {
+      throw new ExpressionVisitException("IOException occoured", e);
+    }
+  }
+
+  @Override
+  public String visitTypeLiteral(EdmType type) throws ExpressionVisitException, ODataApplicationException {
+    try {
+      StringWriter writer = new StringWriter();
+      JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
+      jsonStreamWriter.beginObject().namedStringValueRaw("nodeType", "type").separator()
+          .namedStringValueRaw("type", getTypeString(type)).endObject();
+      writer.flush();
+      return writer.toString();
+    } catch (final IOException e) {
+      throw new ExpressionVisitException("IOException occoured", e);
+    }
+  }
+
+  @Override
+  public String visitLambdaReference(String variableName) throws ExpressionVisitException, ODataApplicationException {
+    try {
+      StringWriter writer = new StringWriter();
+      JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
+      jsonStreamWriter.beginObject().namedStringValueRaw("nodeType", "lambdaReference").separator()
+          .namedStringValueRaw("name", variableName).endObject();
+      writer.flush();
+      return writer.toString();
+    } catch (final IOException e) {
+      throw new ExpressionVisitException("IOException occoured", e);
+    }
+  }
+
+  @Override
+  public String visitEnum(EdmEnumType type, List<String> enumValues) throws ExpressionVisitException,
+      ODataApplicationException {
+    try {
+      StringWriter writer = new StringWriter();
+      JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
+      jsonStreamWriter.beginObject().namedStringValueRaw("nodeType", "enum").separator()
+          .namedStringValueRaw("type", getTypeString(type)).separator();
+      jsonStreamWriter.name("values").beginArray();
+      if (enumValues != null) {
+        boolean first = true;
+        for (String value : enumValues) {
+          if (first) {
+            first = false;
+          } else {
+            jsonStreamWriter.separator();
+          }
+          jsonStreamWriter.stringValue(value);
+        }
+      }
+      jsonStreamWriter.endArray();
+
+      jsonStreamWriter.endObject();
+      writer.flush();
+      return writer.toString();
+    } catch (final IOException e) {
+      throw new ExpressionVisitException("IOException occoured", e);
+    }
+  }
+
+  private String getType(UnaryOperatorKind operator) {
+    switch (operator) {
+    case MINUS:
+      return "Number";
+    case NOT:
+      return "Boolean";
+    default:
+      return "unknown";
+    }
+  }
+
+  private String getType(MethodKind methodCall) {
+    switch (methodCall) {
+    case STARTSWITH:
+    case CONTAINS:
+    case ENDSWITH:
+    case ISOF:
+      return "Boolean";
+    case INDEXOF:
+    case LENGTH:
+    case ROUND:
+    case FLOOR:
+    case CEILING:
+    case DAY:
+    case HOUR:
+    case MINUTE:
+    case MONTH:
+    case SECOND:
+    case FRACTIONALSECONDS:
+      return "Number";
+    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";
+    default:
+      return "unkown";
+    }
+  }
+
+  private void appendUriResourcePartObject(JsonStreamWriter jsonStreamWriter, UriResource segment) throws IOException,
+      ExpressionVisitException, ODataApplicationException {
+    if (segment instanceof UriResourceLambdaAll) {
+      UriResourceLambdaAll all = (UriResourceLambdaAll) segment;
+      String lambdaJsonObjectString = visitLambdaExpression("ALL", all.getLambdaVariable(), all.getExpression());
+      jsonStreamWriter.unquotedValue(lambdaJsonObjectString);
+      return;
+    } else if (segment instanceof UriResourceLambdaAny) {
+      UriResourceLambdaAny any = (UriResourceLambdaAny) segment;
+      String lambdaJsonObjectString = visitLambdaExpression("ANY", any.getLambdaVariable(), any.getExpression());
+      jsonStreamWriter.unquotedValue(lambdaJsonObjectString);
+      return;
+    } else if (segment instanceof UriResourcePartTyped) {
+      String typeName =
+          ((UriResourcePartTyped) segment).getType().getFullQualifiedName().getFullQualifiedNameAsString();
+      jsonStreamWriter.beginObject().namedStringValue("nodeType", segment.getKind().toString()).separator()
+          .namedStringValue("name", segment.toString()).separator().namedStringValueRaw("type", typeName).endObject();
+    } else {
+      jsonStreamWriter.beginObject().namedStringValue("nodeType", segment.getKind().toString()).separator()
+          .namedStringValue("name", segment.toString()).separator().namedStringValueRaw("type", null).endObject();
+    }
+  }
+
+  private String getType(BinaryOperatorKind operator) {
+    switch (operator) {
+    case MUL:
+    case DIV:
+    case MOD:
+    case ADD:
+    case SUB:
+      return "Number";
+
+    case HAS:
+    case GT:
+    case GE:
+    case LT:
+    case LE:
+    case EQ:
+    case NE:
+    case AND:
+    case OR:
+      return "Boolean";
+
+    default:
+      return "unkown";
+    }
+  }
+
+  private String getTypeString(EdmType type) {
+    if (type == null) {
+      return null;
+    }
+    return type.getFullQualifiedName().getFullQualifiedNameAsString();
+  }
+
+  private String getType(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();
+    }
+    return type == null ? "unknown" : type.getFullQualifiedName().getFullQualifiedNameAsString();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0ce9c45d/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
new file mode 100644
index 0000000..113b45d
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/JsonStreamWriter.java
@@ -0,0 +1,175 @@
+/*
+ * 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);
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0ce9c45d/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LiteralImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LiteralImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LiteralImpl.java
index d9db0d4..1dd9fa7 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LiteralImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LiteralImpl.java
@@ -51,7 +51,7 @@ public class LiteralImpl extends ExpressionImpl implements Literal {
 
   @Override
   public <T> T accept(final ExpressionVisitor<T> visitor) throws ExpressionVisitException, ODataApplicationException {
-    return visitor.visitLiteral(text);
+    return visitor.visitLiteral(this);
   }
 
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0ce9c45d/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/ExpressionVisitorImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/ExpressionVisitorImpl.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/ExpressionVisitorImpl.java
index 69ab34a..969a754 100644
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/ExpressionVisitorImpl.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/ExpressionVisitorImpl.java
@@ -36,6 +36,7 @@ import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKin
 import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
 import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException;
 import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitor;
+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 org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operand.TypedOperand;
@@ -167,9 +168,8 @@ public class ExpressionVisitorImpl implements ExpressionVisitor<VisitorOperand>
   }
 
   @Override
-  public VisitorOperand visitLiteral(final String literal) throws ExpressionVisitException, ODataApplicationException {
-
-    return new UntypedOperand(literal);
+  public VisitorOperand visitLiteral(final Literal literal) throws ExpressionVisitException, ODataApplicationException {
+    return new UntypedOperand(literal.getText());
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0ce9c45d/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/FilterTreeToText.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/FilterTreeToText.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/FilterTreeToText.java
index 7b0752f..14ddbc6 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/FilterTreeToText.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/FilterTreeToText.java
@@ -33,6 +33,7 @@ import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKin
 import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
 import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException;
 import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitor;
+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;
 
@@ -82,8 +83,8 @@ public class FilterTreeToText implements ExpressionVisitor<String> {
   }
 
   @Override
-  public String visitLiteral(final String literal) throws ExpressionVisitException {
-    return "<" + literal + ">";
+  public String visitLiteral(final Literal literal) throws ExpressionVisitException {
+    return "<" + literal.getText() + ">";
   }
 
   @Override