WIP json refactor - initial tidy

This commit is contained in:
Rob Bygrave
2014-11-05 23:15:09 +13:00
parent 0ceda6406e
commit b313809894
29 changed files with 1301 additions and 1001 deletions
@@ -2,6 +2,7 @@ package com.avaje.ebeaninternal.server.text.json;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Type;
import java.util.ArrayList;
@@ -13,10 +14,12 @@ import java.util.Map.Entry;
import java.util.Set;
import javax.json.Json;
import javax.json.stream.JsonGenerator;
import javax.json.stream.JsonParser;
import javax.json.stream.JsonParser.Event;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.text.PathProperties;
import com.avaje.ebean.text.TextException;
import com.avaje.ebean.text.json.JsonContext;
import com.avaje.ebean.text.json.JsonElement;
@@ -25,7 +28,6 @@ import com.avaje.ebean.text.json.JsonValueAdapter;
import com.avaje.ebean.text.json.JsonWriteOptions;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.type.EscapeJson;
import com.avaje.ebeaninternal.util.ParamTypeHelper;
import com.avaje.ebeaninternal.util.ParamTypeHelper.ManyType;
import com.avaje.ebeaninternal.util.ParamTypeHelper.TypeInfo;
@@ -37,293 +39,263 @@ import com.avaje.ebeaninternal.util.ParamTypeHelper.TypeInfo;
*/
public class DJsonContext implements JsonContext {
private final SpiEbeanServer server;
private final JsonValueAdapter dfltValueAdapter;
private final boolean dfltPretty;
public DJsonContext(SpiEbeanServer server, JsonValueAdapter dfltValueAdapter, boolean dfltPretty){
this.server = server;
this.dfltValueAdapter = dfltValueAdapter;
this.dfltPretty = dfltPretty;
}
private final SpiEbeanServer server;
public boolean isSupportedType(Type genericType) {
return server.isSupportedType(genericType);
}
//private final JsonValueAdapter dfltValueAdapter;
private JsonParser createReader(Reader jsonReader) {
return Json.createParser(jsonReader);
//return new ReadJsonSourceReader(jsonReader, 256, 512);
}
public <T> T toBean(Class<T> cls, String json){
return toBean(cls, new StringReader(json), null);
}
public <T> T toBean(Class<T> cls, Reader jsonReader) {
return toBean(cls, createReader(jsonReader), null);
}
public <T> T toBean(Class<T> cls, String json, JsonReadOptions options){
return toBean(cls, new StringReader(json), options);
}
private final boolean dfltPretty;
public <T> T toBean(Class<T> cls, Reader jsonReader, JsonReadOptions options) {
return toBean(cls, createReader(jsonReader), options);
}
public DJsonContext(SpiEbeanServer server, JsonValueAdapter dfltValueAdapter, boolean dfltPretty) {
this.server = server;
//this.dfltValueAdapter = dfltValueAdapter;
this.dfltPretty = dfltPretty;
}
// private <T> T toBean(Class<T> cls, ReadJsonSource src, JsonReadOptions options){
//
// BeanDescriptor<T> d = getDecriptor(cls);
// ReadJsonContext ctx = new ReadJsonContext(src, dfltValueAdapter, options);
// return d.jsonReadBean(ctx, null);
// }
public boolean isSupportedType(Type genericType) {
return server.isSupportedType(genericType);
}
private <T> T toBean(Class<T> cls, JsonParser parser, JsonReadOptions options) {
private JsonParser createReader(Reader jsonReader) {
return Json.createParser(jsonReader);
}
public <T> T toBean(Class<T> cls, String json) {
return toBean(cls, new StringReader(json), null);
}
public <T> T toBean(Class<T> cls, Reader jsonReader) {
return toBean(cls, createReader(jsonReader), null);
}
public <T> T toBean(Class<T> cls, String json, JsonReadOptions options) {
return toBean(cls, new StringReader(json), options);
}
public <T> T toBean(Class<T> cls, Reader jsonReader, JsonReadOptions options) {
return toBean(cls, createReader(jsonReader), options);
}
private <T> T toBean(Class<T> cls, JsonParser parser, JsonReadOptions options) {
BeanDescriptor<T> d = getDecriptor(cls);
return d.jsonRead(parser, null);
}
public <T> List<T> toList(Class<T> cls, String json) {
return toList(cls, new StringReader(json), null);
}
public <T> List<T> toList(Class<T> cls, String json, JsonReadOptions options) {
return toList(cls, new StringReader(json), options);
}
public <T> List<T> toList(Class<T> cls, Reader jsonReader) {
return toList(cls, createReader(jsonReader), null);
}
public <T> List<T> toList(Class<T> cls, Reader jsonReader, JsonReadOptions options) {
return toList(cls, createReader(jsonReader), options);
}
private <T> List<T> toList(Class<T> cls, JsonParser src, JsonReadOptions options) {
try {
BeanDescriptor<T> d = getDecriptor(cls);
// ReadJsonContext ctx = new ReadJsonContext(src, dfltValueAdapter, options);
return d.jsonRead(parser, null);
}
public <T> List<T> toList(Class<T> cls, String json){
return toList(cls, new StringReader(json), null);
}
public <T> List<T> toList(Class<T> cls, String json, JsonReadOptions options){
return toList(cls, new StringReader(json), options);
}
public <T> List<T> toList(Class<T> cls, Reader jsonReader){
return toList(cls, createReader(jsonReader), null);
}
List<T> list = new ArrayList<T>();
public <T> List<T> toList(Class<T> cls, Reader jsonReader, JsonReadOptions options){
return toList(cls, createReader(jsonReader), options);
}
private <T> List<T> toList(Class<T> cls, JsonParser src, JsonReadOptions options){
if (!src.hasNext()) {
return list;
}
Event event = src.next();
if (event != Event.START_ARRAY) {
throw new TextException("Expecting start_array event but got [" + event + "] at [" + src.getLocation() + "]");
}
try {
BeanDescriptor<T> d = getDecriptor(cls);
List<T> list = new ArrayList<T>();
//ReadJsonContext ctx = new ReadJsonContext(src, dfltValueAdapter, options);
if (!src.hasNext()) {
return list;
}
Event event = src.next();
if (event != Event.START_ARRAY) {
throw new TextException("Expecting start_array event but got ["+event+"] at ["+src.getLocation()+"]");
}
//ctx.readArrayBegin();
do {
T bean = d.jsonRead(src, null);
if (bean == null){
break;
} else {
list.add(bean);
}
// if (!ctx.readArrayNext()){
// break;
// }
} while(true);
return list;
} catch (RuntimeException e){
throw new TextException("Error parsing "+src, e);
}
}
public Object toObject(Type genericType, String json, JsonReadOptions options) {
TypeInfo info = ParamTypeHelper.getTypeInfo(genericType);
Class<?> beanType = info.getBeanType();
if (JsonElement.class.isAssignableFrom(beanType)){
return InternalJsonParser.parse(json);
}
ManyType manyType = info.getManyType();
switch (manyType) {
case NONE:
return toBean(info.getBeanType(), json, options);
case LIST:
return toList(info.getBeanType(), json, options);
default:
String msg = "ManyType "+manyType+" not supported yet";
throw new TextException(msg);
}
}
public Object toObject(Type genericType, Reader json, JsonReadOptions options) {
TypeInfo info = ParamTypeHelper.getTypeInfo(genericType);
Class<?> beanType = info.getBeanType();
if (JsonElement.class.isAssignableFrom(beanType)){
return InternalJsonParser.parse(json);
}
ManyType manyType = info.getManyType();
switch (manyType) {
case NONE:
return toBean(info.getBeanType(), json, options);
case LIST:
return toList(info.getBeanType(), json, options);
default:
String msg = "ManyType "+manyType+" not supported yet";
throw new TextException(msg);
}
}
public void toJsonWriter(Object o, Writer writer) {
toJsonWriter(o, writer, dfltPretty, null, null);
}
public void toJsonWriter(Object o, Writer writer, boolean pretty) {
toJsonWriter(o, writer, pretty, null, null);
}
public void toJsonWriter(Object o, Writer writer, boolean pretty, JsonWriteOptions options){
toJsonWriter(o, writer, pretty, null, null);
}
public void toJsonWriter(Object o, Writer writer, boolean pretty, JsonWriteOptions options, String callback) {
toJsonInternal(o, new WriteJsonBufferWriter(writer), pretty, options, callback);
}
public String toJsonString(Object o){
return toJsonString(o, dfltPretty, null);
}
public String toJsonString(Object o, boolean pretty){
return toJsonString(o, pretty, null);
}
public String toJsonString(Object o, boolean pretty, JsonWriteOptions options){
return toJsonString(o, pretty, options, null);
}
public String toJsonString(Object o, boolean pretty, JsonWriteOptions options, String callback){
WriteJsonBufferString b = new WriteJsonBufferString();
toJsonInternal(o, b, pretty, options, callback);
return b.getBufferOutput();
}
@SuppressWarnings("unchecked")
private void toJsonInternal(Object o, WriteJsonBuffer buffer, boolean pretty, JsonWriteOptions options, String requestCallback){
if (o == null){
buffer.append("null");
} else if (o instanceof Number) {
buffer.append(o.toString());
} else if (o instanceof Boolean) {
buffer.append(o.toString());
} else if (o instanceof String) {
EscapeJson.escapeQuote(o.toString(), buffer);
} else if (o instanceof JsonElement) {
} else if (o instanceof Map<?,?>){
toJsonFromMap((Map<Object,Object>)o, buffer, pretty, options, requestCallback);
} else if (o instanceof Collection<?>){
toJsonFromCollection((Collection<?>)o, buffer, pretty, options, requestCallback);
do {
T bean = d.jsonRead(src, null);
if (bean == null) {
break;
} else {
BeanDescriptor<?> d = getDecriptor(o.getClass());
WriteJsonContext ctx = new WriteJsonContext(buffer, pretty, dfltValueAdapter, options, requestCallback, server);
d.jsonWrite(ctx, (EntityBean)o);
ctx.end();
list.add(bean);
}
} while (true);
return list;
} catch (RuntimeException e) {
throw new TextException("Error parsing " + src, e);
}
}
private <T> void toJsonFromCollection(Collection<T> c, WriteJsonBuffer buffer, boolean pretty, JsonWriteOptions options, String requestCallback){
Iterator<T> it = c.iterator();
if (!it.hasNext()){
buffer.append("[]");
return;
}
WriteJsonContext ctx = new WriteJsonContext(buffer, pretty, dfltValueAdapter, options, requestCallback, server);
public Object toObject(Type genericType, String json, JsonReadOptions options) {
Object o = it.next();
BeanDescriptor<?> d = getDecriptor(o.getClass());
ctx.appendArrayBegin();
d.jsonWrite(ctx, (EntityBean)o);
while (it.hasNext()) {
ctx.appendComma();
T t = it.next();
d.jsonWrite(ctx, (EntityBean)t);
}
ctx.appendArrayEnd();
ctx.end();
TypeInfo info = ParamTypeHelper.getTypeInfo(genericType);
Class<?> beanType = info.getBeanType();
if (JsonElement.class.isAssignableFrom(beanType)) {
return InternalJsonParser.parse(json);
}
private void toJsonFromMap(Map<Object,Object> map, WriteJsonBuffer buffer, boolean pretty, JsonWriteOptions options, String requestCallback){
if (map.isEmpty()){
buffer.append("{}");
return;
}
WriteJsonContext ctx = new WriteJsonContext(buffer, pretty, dfltValueAdapter, options, requestCallback, server);
ManyType manyType = info.getManyType();
switch (manyType) {
case NONE:
return toBean(info.getBeanType(), json, options);
Set<Entry<Object,Object>> entrySet = map.entrySet();
Iterator<Entry<Object, Object>> it = entrySet.iterator();
Entry<Object, Object> entry = it.next();
case LIST:
return toList(info.getBeanType(), json, options);
ctx.appendObjectBegin();
toJsonMapKey(buffer, false, entry.getKey());
toJsonMapValue(buffer, pretty, options, requestCallback, entry.getValue());
while (it.hasNext()) {
entry = it.next();
ctx.appendComma();
toJsonMapKey(buffer, pretty, entry.getKey());
toJsonMapValue(buffer, pretty, options, requestCallback, entry.getValue());
}
ctx.appendObjectEnd();
ctx.end();
default:
String msg = "ManyType " + manyType + " not supported yet";
throw new TextException(msg);
}
}
public Object toObject(Type genericType, Reader json, JsonReadOptions options) {
TypeInfo info = ParamTypeHelper.getTypeInfo(genericType);
Class<?> beanType = info.getBeanType();
if (JsonElement.class.isAssignableFrom(beanType)) {
return InternalJsonParser.parse(json);
}
private void toJsonMapKey(WriteJsonBuffer buffer, boolean pretty, Object key) {
if (pretty){
buffer.append("\n");
}
buffer.append("\"");
buffer.append(key.toString());
buffer.append("\":");
}
private void toJsonMapValue(WriteJsonBuffer buffer, boolean pretty, JsonWriteOptions options, String requestCallback,
Object value) {
if (value == null){
buffer.append("null");
} else {
toJsonInternal(value, buffer, pretty, options, requestCallback);
}
ManyType manyType = info.getManyType();
switch (manyType) {
case NONE:
return toBean(info.getBeanType(), json, options);
case LIST:
return toList(info.getBeanType(), json, options);
default:
throw new TextException("ManyType " + manyType + " not supported");
}
}
public void toJsonWriter(Object o, Writer writer) {
toJsonWriter(o, writer, dfltPretty, null, null);
}
public void toJsonWriter(Object o, Writer writer, boolean pretty) {
toJsonWriter(o, writer, pretty, null, null);
}
public void toJsonWriter(Object o, Writer writer, boolean pretty, JsonWriteOptions options) {
toJsonWriter(o, writer, pretty, null, null);
}
public void toJsonWriter(Object o, Writer writer, boolean pretty, JsonWriteOptions options, String callback) {
JsonGenerator generator = Json.createGenerator(writer);
toJsonInternal(o, generator, pretty, options, callback);
generator.close();
}
public String toJsonString(Object o) {
return toJsonString(o, dfltPretty, null);
}
public String toJsonString(Object o, boolean pretty) {
return toJsonString(o, pretty, null);
}
public String toJsonString(Object o, boolean pretty, JsonWriteOptions options) {
return toJsonString(o, pretty, options, null);
}
public String toJsonString(Object o, boolean pretty, JsonWriteOptions options, String callback) {
StringWriter writer = new StringWriter(500);
JsonGenerator gen = Json.createGenerator(writer);
toJsonInternal(o, gen, pretty, options, callback);
gen.close();
return writer.toString();
}
@SuppressWarnings("unchecked")
private void toJsonInternal(Object o, JsonGenerator gen, boolean pretty, JsonWriteOptions options, String requestCallback) {
if (o == null) {
gen.writeNull();
} else if (o instanceof Number) {
gen.write(((Number) o).doubleValue());
} else if (o instanceof Boolean) {
gen.write(((Boolean) o).booleanValue());
} else if (o instanceof String) {
gen.write((String) o);
// } else if (o instanceof JsonElement) {
} else if (o instanceof Map<?, ?>) {
toJsonFromMap((Map<Object, Object>) o, gen, pretty, options, requestCallback);
} else if (o instanceof Collection<?>) {
toJsonFromCollection((Collection<?>) o, null, gen, pretty, options, requestCallback);
} else if (o instanceof EntityBean) {
BeanDescriptor<?> d = getDecriptor(o.getClass());
WriteJson writeJson = createWriteJson(gen, options);
d.jsonWrite(writeJson, (EntityBean)o, null);
}
}
private WriteJson createWriteJson(JsonGenerator gen, JsonWriteOptions options) {
PathProperties pathProps = (options == null) ? null : options.getPathProperties();
return new WriteJson(server, gen, pathProps);
}
private <T> void toJsonFromCollection(Collection<T> c, String key, JsonGenerator gen, boolean pretty, JsonWriteOptions options, String requestCallback) {
if (key == null) {
gen.writeStartArray();
} else {
gen.writeStartArray(key);
}
WriteJson writeJson = createWriteJson(gen, options);
Iterator<T> it = c.iterator();
while (it.hasNext()) {
T t = it.next();
BeanDescriptor<?> d = getDecriptor(t.getClass());
//writeJson.setBean();
d.jsonWrite(writeJson, (EntityBean)t, null);
}
gen.writeEnd();
}
private void toJsonFromMap(Map<Object, Object> map, JsonGenerator gen, boolean pretty, JsonWriteOptions options, String requestCallback) {
Set<Entry<Object, Object>> entrySet = map.entrySet();
Iterator<Entry<Object, Object>> it = entrySet.iterator();
WriteJson writeJson = createWriteJson(gen, options);
gen.writeStartObject();
private <T> BeanDescriptor<T> getDecriptor(Class<T> cls) {
BeanDescriptor<T> d = server.getBeanDescriptor(cls);
if (d == null){
String msg = "No BeanDescriptor found for "+cls;
throw new RuntimeException(msg);
while (it.hasNext()) {
Entry<Object, Object> entry = it.next();
String key = entry.getKey().toString();
Object value = entry.getValue();
if (value == null) {
gen.writeNull(key);
} else {
if (value instanceof Collection<?>) {
toJsonFromCollection((Collection<?>) value, key, gen, pretty, options, requestCallback);
} else if (value instanceof EntityBean) {
BeanDescriptor<?> d = getDecriptor(value.getClass());
d.jsonWrite(writeJson,(EntityBean) value, key);
} else {
throw new RuntimeException("TODO process primitive");
}
return d;
}
}
gen.writeEnd();
}
private <T> BeanDescriptor<T> getDecriptor(Class<T> cls) {
BeanDescriptor<T> d = server.getBeanDescriptor(cls);
if (d == null) {
throw new RuntimeException("No BeanDescriptor found for " + cls);
}
return d;
}
}
@@ -4,23 +4,23 @@ import com.avaje.ebeaninternal.server.util.ArrayStack;
public class PathStack extends ArrayStack<String> {
public String peekFullPath(String key){
String prefix = peekWithNull();
if (prefix != null){
return prefix+"."+key;
} else {
return key;
}
}
public void pushPathKey(String key) {
public String peekFullPath(String key) {
String prefix = peekWithNull();
if (prefix != null){
key = prefix+"."+key;
}
push(key);
String prefix = peekWithNull();
if (prefix != null) {
return prefix + "." + key;
} else {
return key;
}
}
public void pushPathKey(String key) {
String prefix = peekWithNull();
if (prefix != null) {
key = prefix + "." + key;
}
push(key);
}
}
@@ -0,0 +1,200 @@
package com.avaje.ebeaninternal.server.text.json;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import javax.json.stream.JsonGenerator;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.text.PathProperties;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.util.ArrayStack;
public class WriteJson {
private final SpiEbeanServer server;
private final JsonGenerator generator;
private final PathProperties pathProperties;
private final PathStack pathStack = new PathStack();
private final ArrayStack<Object> parentBeans = new ArrayStack<Object>();
public WriteJson(SpiEbeanServer server, JsonGenerator generator, PathProperties pathProperties){
this.server = server;
this.generator = generator;
this.pathProperties = pathProperties;
}
public JsonGenerator gen() {
return generator;
}
public boolean isParentBean(Object bean) {
if (parentBeans.isEmpty()) {
return false;
} else {
return parentBeans.contains(bean);
}
}
public void pushParentBeanMany(Object parentBean) {
parentBeans.push(parentBean);
}
public void popParentBeanMany() {
parentBeans.pop();
}
public void beginAssocOne(String key, EntityBean bean) {
parentBeans.push(bean);
pathStack.pushPathKey(key);
}
public void endAssocOne() {
parentBeans.pop();
pathStack.pop();
}
public Set<String> getIncludeProperties() {
if (pathProperties == null) {
return null;
} else {
return pathProperties.get(pathStack.peekWithNull());
}
}
public WriteBean createWriteBean(BeanDescriptor<?> desc, EntityBean bean) {
if (pathProperties == null) {
return new WriteBean(desc, bean);
}
boolean explicitAllProps = false;
Set<String> currentIncludeProps = pathProperties.get(pathStack.peekWithNull());
if (currentIncludeProps != null) {
explicitAllProps = currentIncludeProps.contains("*");
if (explicitAllProps || currentIncludeProps.isEmpty()) {
currentIncludeProps = null;
}
}
return new WriteBean(desc, explicitAllProps, currentIncludeProps, bean);
}
public class WriteBean {
final boolean explicitAllProps;
final Set<String> currentIncludeProps;
final BeanDescriptor<?> desc;
final EntityBean currentBean;
WriteBean(BeanDescriptor<?> desc, EntityBean currentBean){
this(desc, false, null, currentBean);
}
WriteBean(BeanDescriptor<?> desc, boolean explicitAllProps, Set<String> currentIncludeProps, EntityBean currentBean) {
super();
this.desc = desc;
this.currentBean = currentBean;
this.explicitAllProps = explicitAllProps;
this.currentIncludeProps = currentIncludeProps;
}
private boolean isReferenceOnly() {
return !explicitAllProps && currentIncludeProps == null && currentBean._ebean_getIntercept().isReference();
}
private boolean isIncludeProperty(BeanProperty prop) {
if (explicitAllProps)
return true;
if (currentIncludeProps != null) {
// explicitly controlled by pathProperties
return currentIncludeProps.contains(prop.getName());
} else {
// include only loaded properties
return currentBean._ebean_getIntercept().isLoadedProperty(prop.getPropertyIndex());
}
}
public void write(WriteJson writeJson) {
//EntityBean bean = writeJson.getBean();
BeanProperty beanProp = desc.getIdProperty();
if (beanProp != null) {
if (isIncludeProperty(beanProp)) {
beanProp.jsonWrite(writeJson, currentBean);
}
}
if (!isReferenceOnly()) {
// render all the properties and invoke lazy loading if required
BeanProperty[] props = desc.propertiesNonTransient();
for (int j = 0; j < props.length; j++) {
System.out.println("bean "+ currentBean+" prop:"+props[j]);
if (isIncludeProperty(props[j])) {
props[j].jsonWrite(writeJson, currentBean);
}
}
props = desc.propertiesTransient();
for (int j = 0; j < props.length; j++) {
if (isIncludeProperty(props[j])) {
props[j].jsonWrite(writeJson, currentBean);
}
}
}
}
}
public Boolean includeMany(String key) {
if (pathProperties != null) {
String fullPath = pathStack.peekFullPath(key);
return pathProperties.hasPath(fullPath);
}
return null;
}
public void toJson(String name, Collection<?> c) {
beginAssocMany(name);
Iterator<?> it = c.iterator();
while (it.hasNext()) {
EntityBean o = (EntityBean) it.next();
BeanDescriptor<?> d = getDecriptor(o.getClass());
d.jsonWrite(this, o, null);
}
endAssocMany();
}
private <T> BeanDescriptor<T> getDecriptor(Class<T> cls) {
BeanDescriptor<T> d = server.getBeanDescriptor(cls);
if (d == null) {
String msg = "No BeanDescriptor found for " + cls;
throw new RuntimeException(msg);
}
return d;
}
public void beginAssocMany(String key) {
pathStack.pushPathKey(key);
generator.writeStartArray(key);
}
public void endAssocMany() {
pathStack.pop();
generator.writeEnd();
}
public void writeStartObject(String key) {
if (key == null) {
generator.writeStartObject();
} else {
generator.writeStartObject(key);
}
}
}
@@ -1,376 +1,376 @@
package com.avaje.ebeaninternal.server.text.json;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.bean.EntityBeanIntercept;
import com.avaje.ebean.text.PathProperties;
import com.avaje.ebean.text.json.JsonValueAdapter;
import com.avaje.ebean.text.json.JsonWriteBeanVisitor;
import com.avaje.ebean.text.json.JsonWriteOptions;
import com.avaje.ebean.text.json.JsonWriter;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.type.EscapeJson;
import com.avaje.ebeaninternal.server.type.ScalarType;
import com.avaje.ebeaninternal.server.util.ArrayStack;
//import java.util.Collection;
//import java.util.Iterator;
//import java.util.Map;
//import java.util.Set;
//
//import com.avaje.ebean.bean.EntityBean;
//import com.avaje.ebean.bean.EntityBeanIntercept;
//import com.avaje.ebean.text.PathProperties;
//import com.avaje.ebean.text.json.JsonValueAdapter;
//import com.avaje.ebean.text.json.JsonWriteBeanVisitor;
//import com.avaje.ebean.text.json.JsonWriteOptions;
//import com.avaje.ebean.text.json.JsonWriter;
//import com.avaje.ebeaninternal.api.SpiEbeanServer;
//import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
//import com.avaje.ebeaninternal.server.type.EscapeJson;
//import com.avaje.ebeaninternal.server.type.ScalarType;
//import com.avaje.ebeaninternal.server.util.ArrayStack;
public class WriteJsonContext implements JsonWriter {
public class WriteJsonContext {//implements JsonWriter {
private final SpiEbeanServer server;
private final WriteJsonBuffer buffer;
private final boolean pretty;
private final JsonValueAdapter valueAdapter;
private final ArrayStack<Object> parentBeans = new ArrayStack<Object>();
private final PathProperties pathProperties;
private final Map<String, JsonWriteBeanVisitor<?>> visitorMap;
private final String callback;
private final PathStack pathStack;
private WriteBeanState beanState;
private int depthOffset;
boolean assocOne;
public WriteJsonContext(WriteJsonBuffer buffer, boolean pretty, JsonValueAdapter dfltValueAdapter,
JsonWriteOptions options, String requestCallback, SpiEbeanServer server){
this.server = server;
this.buffer = buffer;
this.pretty = pretty;
this.pathStack = new PathStack();
this.callback = getCallback(requestCallback, options);
if (options == null){
this.valueAdapter = dfltValueAdapter;
this.visitorMap = null;
this.pathProperties = null;
} else {
this.valueAdapter = getValueAdapter(dfltValueAdapter, options.getValueAdapter());
this.visitorMap = emptyToNull(options.getVisitorMap());
this.pathProperties = emptyToNull(options.getPathProperties());
}
if (callback != null){
buffer.append(requestCallback).append("(");
}
}
public void toJson(String name, Collection<?> c) {
beginAssocMany(name);
Iterator<?> it = c.iterator();
if (!it.hasNext()){
endAssocMany();
return;
}
EntityBean o = (EntityBean)it.next();
BeanDescriptor<?> d = getDecriptor(o.getClass());
d.jsonWrite(this, o);
while (it.hasNext()) {
appendComma();
EntityBean t = (EntityBean)it.next();
d.jsonWrite(this, t);
}
endAssocMany();
}
private <T> BeanDescriptor<T> getDecriptor(Class<T> cls) {
BeanDescriptor<T> d = server.getBeanDescriptor(cls);
if (d == null){
String msg = "No BeanDescriptor found for "+cls;
throw new RuntimeException(msg);
}
return d;
}
public void appendRawValue(String key, String rawJsonValue) {
appendKeyWithComma(key, true);
buffer.append(rawJsonValue);
}
public void appendQuoteEscapeValue(String key, String valueToEscape) {
appendKeyWithComma(key, true);
EscapeJson.escapeQuote(valueToEscape, buffer);
}
public void end() {
if (callback != null){
buffer.append(")");
}
}
private <MK,MV> Map<MK,MV> emptyToNull(Map<MK,MV> m){
if ( m == null || m.isEmpty()) {
return null;
} else {
return m;
}
}
private PathProperties emptyToNull(PathProperties m){
if ( m == null || m.isEmpty()) {
return null;
} else {
return m;
}
}
private String getCallback(String requestCallback, JsonWriteOptions options) {
if (requestCallback != null){
return requestCallback;
}
if (options != null){
return options.getCallback();
}
return null;
}
private JsonValueAdapter getValueAdapter(JsonValueAdapter dfltValueAdapter, JsonValueAdapter valueAdapter) {
return valueAdapter == null ? dfltValueAdapter : valueAdapter;
}
/**
* Return the set of properties to write to JSON. If null is returned then
* the default will output the properties loaded for this bean.
*/
public Set<String> getIncludeProperties() {
if (pathProperties != null){
String path = pathStack.peekWithNull();
return pathProperties.get(path);
}
return null;
}
public JsonWriteBeanVisitor<?> getBeanVisitor() {
if (visitorMap != null){
String path = pathStack.peekWithNull();
return visitorMap.get(path);
}
return null;
}
public String getJson() {
return buffer.toString();
}
private void appendIndent(){
buffer.append("\n");
int depth = depthOffset + parentBeans.size();
for (int i = 0; i < depth; i++) {
buffer.append(" ");
}
}
public void appendObjectBegin(){
if (pretty && !assocOne){
appendIndent();
}
buffer.append("{");
}
public void appendObjectEnd(){
buffer.append("}");
}
public void appendArrayBegin(){
if (pretty){
appendIndent();
}
buffer.append("[");
depthOffset++;
}
public void appendArrayEnd(){
depthOffset--;
if (pretty){
appendIndent();
}
buffer.append("]");
}
public void appendComma(){
buffer.append(",");
}
public void addDepthOffset(int offset){
depthOffset += offset;
}
public void beginAssocOneIsNull(String key) {
depthOffset++;
internalAppendKeyBegin(key);
appendNull();
depthOffset--;
}
public void beginAssocOne(String key) {
pathStack.pushPathKey(key);
internalAppendKeyBegin(key);
assocOne = true;
}
public void endAssocOne() {
pathStack.pop();
assocOne = false;
}
public Boolean includeMany(String key) {
if (pathProperties != null){
String fullPath = pathStack.peekFullPath(key);
return pathProperties.hasPath(fullPath);
}
return null;
}
public void beginAssocMany(String key) {
pathStack.pushPathKey(key);
depthOffset--;
internalAppendKeyBegin(key);
depthOffset++;
buffer.append("[");
}
public void endAssocMany(){
pathStack.pop();
if (pretty){
depthOffset--;
appendIndent();
depthOffset++;
}
buffer.append("]");
}
private void internalAppendKeyBegin(String key) {
if (!beanState.isFirstKey()){
buffer.append(",");
}
if (pretty){
appendIndent();
}
appendKeyWithComma(key, false);
}
public <T> void appendNameValue(String key, ScalarType<T> scalarType, T value) {
appendKeyWithComma(key, true);
scalarType.jsonWrite(buffer, value, getValueAdapter());
}
public void appendDiscriminator(String key, String discValue) {
appendKeyWithComma(key, true);
buffer.append("\"");
buffer.append(discValue);
buffer.append("\"");
}
private void appendKeyWithComma(String key, boolean withComma) {
if (withComma){
if (!beanState.isFirstKey()){
buffer.append(",");
}
}
buffer.append("\"");
if(key == null) {
buffer.append("null");
} else {
buffer.append(key);
}
buffer.append("\":");
}
public void appendNull(String key) {
appendKeyWithComma(key, true);
buffer.append("null");
}
public void appendNull() {
buffer.append("null");
}
public JsonValueAdapter getValueAdapter() {
return valueAdapter;
}
public String toString() {
return buffer.toString();
}
public void popParentBean(){
parentBeans.pop();
}
public void pushParentBean(Object parentBean){
parentBeans.push(parentBean);
}
public void popParentBeanMany(){
parentBeans.pop();
depthOffset--;
}
public void pushParentBeanMany(Object parentBean){
parentBeans.push(parentBean);
depthOffset++;
}
public boolean isParentBean(Object bean){
if (parentBeans.isEmpty()){
return false;
} else {
return parentBeans.contains(bean);
}
}
public WriteBeanState pushBeanState(Object bean) {
WriteBeanState newState = new WriteBeanState();//bean);
WriteBeanState prevState = beanState;
beanState = newState;
return prevState;
}
public void pushPreviousState(WriteBeanState previousState) {
this.beanState = previousState;
}
public static class WriteBeanState {
private boolean firstKeyOut;
public WriteBeanState() {
}
public boolean isFirstKey() {
if (!firstKeyOut){
firstKeyOut = true;
return true;
} else {
return false;
}
}
}
// private final SpiEbeanServer server;
//
// private final WriteJsonBuffer buffer;
//
// private final boolean pretty;
//
// private final JsonValueAdapter valueAdapter;
//
// private final ArrayStack<Object> parentBeans = new ArrayStack<Object>();
//
// private final PathProperties pathProperties;
//
// private final Map<String, JsonWriteBeanVisitor<?>> visitorMap;
//
// private final String callback;
//
// private final PathStack pathStack;
//
// private WriteBeanState beanState;
//
// private int depthOffset;
//
// boolean assocOne;
//
// public WriteJsonContext(WriteJsonBuffer buffer, boolean pretty, JsonValueAdapter dfltValueAdapter,
// JsonWriteOptions options, String requestCallback, SpiEbeanServer server){
//
// this.server = server;
// this.buffer = buffer;
// this.pretty = pretty;
// this.pathStack = new PathStack();
// this.callback = getCallback(requestCallback, options);
// if (options == null){
// this.valueAdapter = dfltValueAdapter;
// this.visitorMap = null;
// this.pathProperties = null;
//
// } else {
// this.valueAdapter = getValueAdapter(dfltValueAdapter, options.getValueAdapter());
// this.visitorMap = emptyToNull(options.getVisitorMap());
// this.pathProperties = emptyToNull(options.getPathProperties());
// }
//
// if (callback != null){
// buffer.append(requestCallback).append("(");
// }
// }
//
// public void toJson(String name, Collection<?> c) {
//
// beginAssocMany(name);
//
// Iterator<?> it = c.iterator();
// if (!it.hasNext()){
// endAssocMany();
// return;
// }
//
// EntityBean o = (EntityBean)it.next();
// BeanDescriptor<?> d = getDecriptor(o.getClass());
//
// d.jsonWrite(this, o);
// while (it.hasNext()) {
// appendComma();
// EntityBean t = (EntityBean)it.next();
// d.jsonWrite(this, t);
// }
// endAssocMany();
// }
//
// private <T> BeanDescriptor<T> getDecriptor(Class<T> cls) {
// BeanDescriptor<T> d = server.getBeanDescriptor(cls);
// if (d == null){
// String msg = "No BeanDescriptor found for "+cls;
// throw new RuntimeException(msg);
// }
// return d;
// }
//
// public void appendRawValue(String key, String rawJsonValue) {
// appendKeyWithComma(key, true);
// buffer.append(rawJsonValue);
// }
//
// public void appendQuoteEscapeValue(String key, String valueToEscape) {
// appendKeyWithComma(key, true);
// EscapeJson.escapeQuote(valueToEscape, buffer);
// }
//
// public void end() {
// if (callback != null){
// buffer.append(")");
// }
// }
//
// private <MK,MV> Map<MK,MV> emptyToNull(Map<MK,MV> m){
// if ( m == null || m.isEmpty()) {
// return null;
// } else {
// return m;
// }
// }
//
// private PathProperties emptyToNull(PathProperties m){
// if ( m == null || m.isEmpty()) {
// return null;
// } else {
// return m;
// }
// }
//
// private String getCallback(String requestCallback, JsonWriteOptions options) {
// if (requestCallback != null){
// return requestCallback;
// }
// if (options != null){
// return options.getCallback();
// }
// return null;
// }
//
// private JsonValueAdapter getValueAdapter(JsonValueAdapter dfltValueAdapter, JsonValueAdapter valueAdapter) {
// return valueAdapter == null ? dfltValueAdapter : valueAdapter;
// }
//
// /**
// * Return the set of properties to write to JSON. If null is returned then
// * the default will output the properties loaded for this bean.
// */
// public Set<String> getIncludeProperties() {
// if (pathProperties != null){
// String path = pathStack.peekWithNull();
// return pathProperties.get(path);
// }
// return null;
// }
//
// public JsonWriteBeanVisitor<?> getBeanVisitor() {
// if (visitorMap != null){
// String path = pathStack.peekWithNull();
// return visitorMap.get(path);
// }
// return null;
// }
//
// public String getJson() {
// return buffer.toString();
// }
//
// private void appendIndent(){
//
// buffer.append("\n");
// int depth = depthOffset + parentBeans.size();
// for (int i = 0; i < depth; i++) {
// buffer.append(" ");
// }
// }
//
// public void appendObjectBegin(){
// if (pretty && !assocOne){
// appendIndent();
// }
// buffer.append("{");
// }
// public void appendObjectEnd(){
// buffer.append("}");
// }
//
// public void appendArrayBegin(){
// if (pretty){
// appendIndent();
// }
// buffer.append("[");
// depthOffset++;
// }
//
// public void appendArrayEnd(){
// depthOffset--;
// if (pretty){
// appendIndent();
// }
// buffer.append("]");
// }
//
// public void appendComma(){
// buffer.append(",");
// }
//
// public void addDepthOffset(int offset){
// depthOffset += offset;
// }
//
// public void beginAssocOneIsNull(String key) {
// depthOffset++;
// internalAppendKeyBegin(key);
// appendNull();
// depthOffset--;
// }
//
// public void beginAssocOne(String key) {
// pathStack.pushPathKey(key);
//
// internalAppendKeyBegin(key);
// assocOne = true;
// }
//
// public void endAssocOne() {
//
// pathStack.pop();
// assocOne = false;
// }
//
// public Boolean includeMany(String key) {
// if (pathProperties != null){
// String fullPath = pathStack.peekFullPath(key);
// return pathProperties.hasPath(fullPath);
// }
// return null;
// }
//
// public void beginAssocMany(String key) {
//
// pathStack.pushPathKey(key);
//
// depthOffset--;
// internalAppendKeyBegin(key);
// depthOffset++;
// buffer.append("[");
// }
//
// public void endAssocMany(){
//
// pathStack.pop();
//
// if (pretty){
// depthOffset--;
// appendIndent();
// depthOffset++;
// }
// buffer.append("]");
// }
//
// private void internalAppendKeyBegin(String key) {
// if (!beanState.isFirstKey()){
// buffer.append(",");
// }
// if (pretty){
// appendIndent();
// }
// appendKeyWithComma(key, false);
// }
//
// public <T> void appendNameValue(String key, ScalarType<T> scalarType, T value) {
// appendKeyWithComma(key, true);
// scalarType.jsonWrite(buffer, value, getValueAdapter());
// }
//
// public void appendDiscriminator(String key, String discValue) {
// appendKeyWithComma(key, true);
// buffer.append("\"");
// buffer.append(discValue);
// buffer.append("\"");
// }
//
// private void appendKeyWithComma(String key, boolean withComma) {
// if (withComma){
// if (!beanState.isFirstKey()){
// buffer.append(",");
// }
// }
// buffer.append("\"");
// if(key == null) {
// buffer.append("null");
// } else {
// buffer.append(key);
// }
// buffer.append("\":");
// }
//
// public void appendNull(String key) {
// appendKeyWithComma(key, true);
// buffer.append("null");
// }
//
// public void appendNull() {
// buffer.append("null");
// }
//
// public JsonValueAdapter getValueAdapter() {
// return valueAdapter;
// }
//
// public String toString() {
// return buffer.toString();
// }
//
// public void popParentBean(){
// parentBeans.pop();
// }
//
// public void pushParentBean(Object parentBean){
// parentBeans.push(parentBean);
// }
//
// public void popParentBeanMany(){
// parentBeans.pop();
// depthOffset--;
// }
//
// public void pushParentBeanMany(Object parentBean){
// parentBeans.push(parentBean);
// depthOffset++;
// }
//
// public boolean isParentBean(Object bean){
// if (parentBeans.isEmpty()){
// return false;
// } else {
// return parentBeans.contains(bean);
// }
// }
//
// public WriteBeanState pushBeanState(Object bean) {
// WriteBeanState newState = new WriteBeanState();//bean);
// WriteBeanState prevState = beanState;
// beanState = newState;
// return prevState;
// }
//
// public void pushPreviousState(WriteBeanState previousState) {
// this.beanState = previousState;
// }
//
//
// public static class WriteBeanState {
//
// private boolean firstKeyOut;
//
// public WriteBeanState() {
//
// }
//
// public boolean isFirstKey() {
// if (!firstKeyOut){
// firstKeyOut = true;
// return true;
// } else {
// return false;
// }
// }
//
// }
}