refactor json-only classes

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@1484901 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Pinaki Poddar 2013-05-21 18:47:15 +00:00
parent 937aad666b
commit ede84e683e
3 changed files with 297 additions and 0 deletions

View File

@ -0,0 +1,54 @@
/*
* 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.openjpa.json;
/**
* A generic interface for a JSON encoded instance.
*
* @author Pinaki Poddar
*
*/
public interface JSON {
/**
* Render into a string buffer.
*
* @param level level at which this instance is being rendered
* @return a mutable buffer
*/
public StringBuilder asString(int level);
public static final char FIELD_SEPARATOR = ',';
public static final char MEMBER_SEPARATOR = ',';
public static final char VALUE_SEPARATOR = ':';
public static final char IOR_SEPARTOR = '-';
public static final char QUOTE = '"';
public static final char SPACE = ' ';
public static final char OBJECT_START = '{';
public static final char OBJECT_END = '}';
public static final char ARRAY_START = '[';
public static final char ARRAY_END = ']';
public static final String NEWLINE = "\r\n";
public static final String NULL_LITERAL = "null";
public static final String REF_MARKER = "$ref";
public static final String ID_MARKER = "$id";
public static final String ARRAY_EMPTY = "[]";
}

View File

@ -0,0 +1,241 @@
/*
* 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.openjpa.json;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* A JSON instance for persistence.
* <br>
* Persistent instances have a persistent identity that extends beyond the process lifetime unlike other common
* identity such as {@linkplain System#identityHashCode(Object) identity hash code} for a Java instance in a JVM.
* <br>
* A JSONObject instance must need such a persistent identity.
*
* @author Pinaki Poddar
*
*/
public class JSONObject implements JSON {
private final String _type;
private final String _id;
private final boolean _ref;
private final Map<String, Object> _values;
public JSONObject(String type, Object id, boolean ref) {
_type = type;
_id = id.toString();
_ref = ref;
_values = new LinkedHashMap<String, Object>();
}
public void set(String key, Object value) {
_values.put(key, value);
}
public void write(PrintWriter writer) {
writer.println(toString());
}
public String toString() {
return asString(0).toString();
}
public StringBuilder asString(int indent) {
StringBuilder buf = new StringBuilder().append(OBJECT_START);
buf.append(encodeField(_ref ? REF_MARKER : ID_MARKER, ior(), 0));
if (_ref) {
return buf.append(OBJECT_END);
}
StringBuilder tab = newIndent(indent+1);
for (Map.Entry<String, Object> e : _values.entrySet()) {
buf.append(FIELD_SEPARATOR).append(NEWLINE);
buf.append(tab).append(encodeField(e.getKey(), e.getValue(), indent+1));
}
buf.append(NEWLINE)
.append(newIndent(indent))
.append(OBJECT_END);
return buf;
}
/**
* Encoding a JSON field is a quoted field name, followed by a :, followed by a value (which itself can be JSON)
* @param field
* @param value
* @param indent
* @return
*/
private static StringBuilder encodeField(String field, Object value, int indent) {
return new StringBuilder()
.append(quoteFieldName(field))
.append(VALUE_SEPARATOR)
.append(quoteFieldValue(value, indent));
}
private static StringBuilder newIndent(int indent) {
char[] tabs = new char[indent*4];
Arrays.fill(tabs, SPACE);
return new StringBuilder().append(tabs);
}
StringBuilder ior() {
return new StringBuilder(_type).append('-').append(_id);
}
private static StringBuilder quoteFieldName(String s) {
return new StringBuilder().append(QUOTE).append(s).append(QUOTE);
}
/**
* Creates a StringBuilder for the given value.
* If the value is null, outputs <code>null</code> without quote
* If the value is Number, outputs the value without quote
* If the value is JSON, outputs the string rendition of value
* Otherwise quoted value
* @param o
* @return
*/
private static StringBuilder quoteFieldValue(Object o, int indent) {
if (o == null) return new StringBuilder(NULL_LITERAL);
if (o instanceof Number) return new StringBuilder(o.toString());
if (o instanceof JSON) return ((JSON)o).asString(indent);
return quoted(o.toString());
}
private static StringBuilder quoted(Object o) {
if (o == null) return new StringBuilder(NULL_LITERAL);
return new StringBuilder().append(QUOTE).append(o.toString()).append(QUOTE);
}
/**
* An array of objects. Members can be JSON too.
*
* @author Pinaki Poddar
*
*/
public static class Array implements JSON {
private List<Object> _members = new ArrayList<Object>();
public void add(Object o) {
_members.add(o);
}
public String toString() {
return asString(0).toString();
}
public StringBuilder asString(int indent) {
StringBuilder buf = new StringBuilder().append(ARRAY_START);
StringBuilder tab = JSONObject.newIndent(indent+1);
for (Object o : _members) {
if (buf.length() > 1) buf.append(MEMBER_SEPARATOR);
buf.append(NEWLINE).append(tab);
if (o instanceof JSON)
buf.append(((JSON)o).asString(indent+1));
else
buf.append(o);
}
buf.append(NEWLINE)
.append(JSONObject.newIndent(indent))
.append(ARRAY_END);
return buf;
}
}
/**
* A map whose key or value can be JSON.
* A map is encoded as JSON as an array of entries. Each entry is a key value pair separated with :
*
* @author Pinaki Poddar
*
*/
public static class KVMap implements JSON {
private Map<Object,Object> _entries = new LinkedHashMap<Object,Object>();
public void put(Object k, Object v) {
_entries.put(k,v);
}
public String toString() {
return asString(0).toString();
}
public StringBuilder asString(int indent) {
StringBuilder buf = new StringBuilder().append(ARRAY_START);
StringBuilder tab = JSONObject.newIndent(indent+1);
for (Map.Entry<Object, Object> e : _entries.entrySet()) {
if (buf.length() > 1) buf.append(MEMBER_SEPARATOR);
buf.append(NEWLINE).append(tab);
Object key = e.getKey();
if (key instanceof JSON) {
buf.append(((JSON)key).asString(indent+1));
} else {
buf.append(key);
}
buf.append(VALUE_SEPARATOR);
Object value = e.getValue();
if (value instanceof JSON) {
buf.append(((JSON)value).asString(indent+2));
} else {
buf.append(value);
}
}
buf.append(NEWLINE)
.append(JSONObject.newIndent(indent))
.append(ARRAY_END);
return buf;
}
}
public static void main(String[] args) throws Exception {
JSONObject o = new JSONObject("Person", 1234, false);
JSONObject r = new JSONObject("Person", 1234, true);
JSONObject f = new JSONObject("Person", 2345, false);
Array a = new Array();
a.add(f);
a.add(3456);
a.add(null);
a.add(r);
a.add(null);
KVMap map = new KVMap();
map.put("k1", r);
map.put("k2", f);
map.put("k3", null);
map.put("k4", 3456);
map.put(null, 6789);
f.set("name", "Mary");
f.set("age", 30);
f.set("friend", r);
o.set("name", "John");
o.set("age", 20);
o.set("friend", f);
o.set("friends", a);
o.set("map", map);
System.err.println(o);
}
}

View File

@ -38,6 +38,8 @@ import java.util.Set;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.Metamodel;
import org.apache.openjpa.json.JSON;
import org.apache.openjpa.json.JSONObject;
import org.apache.openjpa.kernel.OpenJPAStateManager;
import org.apache.openjpa.kernel.StoreContext;
import org.apache.openjpa.meta.FieldMetaData;