com.javanut.json.encode.JSONBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pronghorn-pipes Show documentation
Show all versions of pronghorn-pipes Show documentation
Ring buffer based queuing utility for applications that require high performance and/or a small
footprint. Well suited for embedded and stream based processing.
package com.javanut.json.encode;
import com.javanut.json.JSONType;
import com.javanut.json.encode.function.IterBoolFunction;
import com.javanut.json.encode.function.IterDoubleFunction;
import com.javanut.json.encode.function.IterEnumFunction;
import com.javanut.json.encode.function.IterLongFunction;
import com.javanut.json.encode.function.IterMemberFunction;
import com.javanut.json.encode.function.IterStringFunction;
import com.javanut.json.encode.function.IteratorFunction;
import com.javanut.json.encode.function.ToBoolFunction;
import com.javanut.json.encode.function.ToDoubleFunction;
import com.javanut.json.encode.function.ToEnumFunction;
import com.javanut.json.encode.function.ToLongFunction;
import com.javanut.json.encode.function.ToMemberFunction;
import com.javanut.json.encode.function.ToStringFunction;
import com.javanut.pronghorn.pipe.PipeWriter;
import com.javanut.pronghorn.util.AppendableByteWriter;
import com.javanut.pronghorn.util.Appendables;
import com.javanut.pronghorn.util.ByteWriter;
import com.javanut.pronghorn.util.template.StringTemplateBranching;
import com.javanut.pronghorn.util.template.StringTemplateBuilder;
import com.javanut.pronghorn.util.template.StringTemplateIterScript;
import com.javanut.pronghorn.util.template.StringTemplateScript;
// TODO: support rational, decimal
// TODO: implement the primitive type converters, or refactor to use lambdas, or delete methods
// TODO: refactor for duplicate code
// TODO: determine use case for recursive array and either uncomment/test or delete methods
// TODO: implement select as an array element
// Maintain no dependencies to the public API classes (i.e. JSONObject)
class JSONBuilder extends StringTemplateScript {
// Do not store mutable state used during render.
// Use ThreadLocal if required.
private final StringTemplateBuilder scripts;
private final JSONKeywords kw;
private final int depth;
private JSONBuilder root;
// Stored between declaration calls and consumed on use in declaration
private byte[] declaredMemberName;
// In order to support tryCase, we need a render state for objects.
private ObjectRenderState ors;
JSONBuilder() {
this(new StringTemplateBuilder(), JSONKeywords.instance, 0, null);
}
JSONBuilder(JSONKeywords kw) {
this(new StringTemplateBuilder(), kw, 0, null);
}
private JSONBuilder(StringTemplateBuilder scripts, JSONKeywords kw, int depth, JSONBuilder root) {
this.scripts = scripts;
this.kw = kw;
this.depth = depth;
this.root = root;
if (root == null) {
this.root = (JSONBuilder)this;
}
}
void start() {
kw.Start(scripts, depth);
}
void complete() {
kw.Complete(scripts, depth);
}
public void render(AppendableByteWriter writer, T source) {
StringTemplateBuilder.render(scripts,writer, source);
}
// Object Helpers
JSONBuilder addFieldPrefix(String name) {
this.declaredMemberName = name.getBytes();
return this;
}
JSONBuilder addFieldPrefix(byte[] utf8EncodedName) {
this.declaredMemberName = utf8EncodedName;
return this;
}
private static class ObjectRenderState {
private final JSONKeywords kw;
private int objectElementIndex = -1;
ObjectRenderState(JSONKeywords kw) {
this.kw = kw;
}
private void beginObjectRender() {
objectElementIndex = -1;
}
void prefixObjectMemberName(byte[] declaredMemberName, int depth, ByteWriter writer) {
objectElementIndex++;
if (objectElementIndex == 0) {
kw.FirstObjectElement(writer, depth);
}
else {
kw.NextObjectElement(writer, depth);
}
writer.write(declaredMemberName);
kw.ObjectValue(writer, depth);
}
}
private void prefixObjectMemberName(byte[] declaredMemberName, int depth, ByteWriter writer) {
if (declaredMemberName != null && this.ors != null) {
ObjectRenderState ors = this.ors;
if (ors != null) {
ors.prefixObjectMemberName(declaredMemberName, depth, writer);
}
}
}
private StringTemplateScript createNullObjectScript(final byte[] declaredMemberName) {
return new StringTemplateScript() {
@Override
public void render(AppendableByteWriter writer, T source) {
prefixObjectMemberName(declaredMemberName, depth, writer);
kw.Null(writer);
}
};
}
private byte[] consumeDeclaredMemberName() {
byte[] declaredMemberName = this.declaredMemberName;
this.declaredMemberName = null;
return declaredMemberName;
}
// Array Helpers
interface RenderIteration {
void render(AppendableByteWriter appendable, M member, int i);
}
private void iterate(
final IteratorFunction iterator,
final boolean checkNull,
final IterMemberFunction accessor,
final RenderIteration func) {
scripts.add(new StringTemplateIterScript() {
@Override
public boolean render(AppendableByteWriter> writer, T source, int i) {
N node = iterator.get(source, i);
if (node != null) {
if (i > 0) {
kw.NextArrayElement(writer, depth);
}
M member = accessor.get(source, i);
if (checkNull && member == null) {
kw.Null(writer);
} else {
func.render(writer, member, i);
}
return true;
}
return false;
}
});
}
private void iterate(
final IteratorFunction iterator,
final IterBoolFunction isNull,
final RenderIteration func) {
scripts.add(new StringTemplateIterScript() {
@Override
public boolean render(final AppendableByteWriter> writer, T source, int i) {
N node = iterator.get(source, i);
if (node != null) {
if (i > 0) {
kw.NextArrayElement(writer, depth);
}
if (isNull != null && isNull.applyAsBool(source, i)) {
kw.Null(writer);
} else {
func.render(writer, source, i);
}
return true;
}
return false;
}
});
}
// Sub Builders
void addBuilder(final JSONBuilder, M> builder, final ToMemberFunction accessor) {
final byte[] declaredMemberName = consumeDeclaredMemberName();
scripts.add(new StringTemplateScript() {
@Override
public void render(AppendableByteWriter writer, T source) {
prefixObjectMemberName(declaredMemberName, depth, writer);
M member = accessor.get(source);
if (member == null) {
kw.Null(writer);
}
else {
builder.render(writer, member);
}
}
});
}
void recurseRoot(final ToMemberFunction accessor) {
if (root != this) {
addBuilder(root, accessor);
}
}
void addBuilder(final IteratorFunction iterator, final JSONBuilder, M> builder, final IterMemberFunction accessor) {
iterate(iterator, true, accessor, new RenderIteration() {
@Override
public void render(AppendableByteWriter writer, M m, int i) {
builder.render(writer, m);
}
});
}
/*
void recurseRoot(final IteratorFunction iterator, final IterMemberFunction accessor) {
addBuilder(iterator, root, accessor);
}
*/
// Select
JSONBuilder beginSelect() {
final byte[] declaredMemberName = consumeDeclaredMemberName();
JSONBuilder builder = new JSONBuilder(new StringTemplateBuilder(), kw, depth, root);
builder.declaredMemberName = declaredMemberName;
builder.ors = ors;
this.scripts.add(builder);
return builder;
}
JSONBuilder tryCase() {
final byte[] declaredMemberName = this.declaredMemberName; // Do not consume for other try
JSONBuilder builder = new JSONBuilder(new StringTemplateBuilder(), kw, depth, root);
builder.declaredMemberName = declaredMemberName;
builder.ors = ors;
return builder;
}
void endSelect(final int count, final ToBoolFunction[] branches, final JSONBuilder, T>[] cases) {
consumeDeclaredMemberName();
final StringTemplateScript[] caseScripts = new StringTemplateScript[count];
for (int i = 0; i < count; i++) {
final JSONBuilder, T> builder = cases[i];
caseScripts[i] = builder;
}
scripts.add(caseScripts, new StringTemplateBranching() {
@Override
public int branch(T source) {
for (int i = 0; i < count; i++) {
if (branches[i].applyAsBool(source)) {
return i;
}
}
return -1;
}
});
}
void endSelect(IteratorFunction iterator, int count, final IterBoolFunction[] branches, final JSONBuilder, T>[] cases) {
}
// Object
public JSONBuilder beginObject(final ToMemberFunction accessor) {
final byte[] declaredMemberName = consumeDeclaredMemberName();
final StringTemplateBuilder accessorScript = new StringTemplateBuilder<>();
kw.OpenObj(accessorScript, depth);
final ObjectRenderState newOrs = new ObjectRenderState(kw);
final StringTemplateScript objNullBranch = createNullObjectScript(declaredMemberName);
final StringTemplateScript notNullBranch = new StringTemplateScript() {
@Override
public void render(AppendableByteWriter writer, T source) {
prefixObjectMemberName(declaredMemberName, depth, writer);
newOrs.beginObjectRender();
accessorScript.render(writer, accessor.get(source));
}
};
final StringTemplateScript[] nullableBranches = new StringTemplateScript[2];
nullableBranches[0] = objNullBranch;
nullableBranches[1] = notNullBranch;
scripts.add(nullableBranches, new StringTemplateBranching() {
@Override
public int branch(T o) {
return accessor.get(o) == null ? 0 : 1;
}
});
JSONBuilder builder = new JSONBuilder<>(accessorScript, kw, depth + 1, root);
builder.ors = newOrs;
return builder;
}
JSONBuilder beginObject(final IteratorFunction iterator, final IterMemberFunction accessor) {
final StringTemplateBuilder accessorBranch = new StringTemplateBuilder<>();
kw.OpenObj(accessorBranch, depth);
final ObjectRenderState newOrs = new ObjectRenderState(kw);
iterate(iterator, true, new IterMemberFunction() {
@Override
public M get(T o, int i) {
newOrs.beginObjectRender();
return accessor.get(o, i);
}
}, new RenderIteration() {
@Override
public void render(AppendableByteWriter writer, M m, int i) {
accessorBranch.render(writer, m);
}
});
JSONBuilder builder = new JSONBuilder<>(accessorBranch, kw, depth + 1, root);
builder.ors = newOrs;
return builder;
}
void endObject() {
kw.CloseObj(scripts, depth);
}
// Array
JSONBuilder beginArray(final ToMemberFunction func) {
final byte[] declaredMemberName = consumeDeclaredMemberName();
final StringTemplateBuilder arrayBuilder = new StringTemplateBuilder<>();
kw.OpenArray(arrayBuilder, depth);
final StringTemplateScript objNullBranch = createNullObjectScript(declaredMemberName);
final StringTemplateScript notNullBranch = new StringTemplateScript() {
@Override
public void render(AppendableByteWriter writer, T source) {
prefixObjectMemberName(declaredMemberName, depth, writer);
arrayBuilder.render(writer, func.get(source));
}
};
final StringTemplateScript[] nullableBranches = new StringTemplateScript[2];
nullableBranches[0] = objNullBranch;
nullableBranches[1] = notNullBranch;
scripts.add(nullableBranches, new StringTemplateBranching() {
@Override
public int branch(T o) {
return func.get(o) == null ? 0 : 1;
}
});
return new JSONBuilder(arrayBuilder, kw, depth + 1, root);
}
public JSONBuilder beginArray(final IteratorFunction iterator, final IterMemberFunction func) {
final StringTemplateBuilder notNullBranch = new StringTemplateBuilder<>();
kw.OpenArray(notNullBranch, depth);
iterate(iterator, true, func, new RenderIteration() {
@Override
public void render(AppendableByteWriter writer, M m, int i) {
notNullBranch.render(writer, m);
}
});
return new JSONBuilder(notNullBranch, kw, depth + 1, root);
}
void endArray() {
kw.CloseArray(scripts, depth);
}
// Null
void addNull() {
final byte[] declaredMemberName = consumeDeclaredMemberName();
scripts.add(createNullObjectScript(declaredMemberName));
}
void addNull(final IteratorFunction iterator) {
iterate(iterator, new IterBoolFunction() {
@Override
public boolean applyAsBool(T o, int i) {
return true;
}
}, null);
}
// Bool
void addBool(final ToBoolFunction isNull, final ToBoolFunction func) {
final byte[] declaredMemberName = consumeDeclaredMemberName();
scripts.add(new StringTemplateScript() {
@Override
public void render(final AppendableByteWriter writer, T source) {
prefixObjectMemberName(declaredMemberName, depth, writer);
if (isNull != null && isNull.applyAsBool(source)) {
kw.Null(writer);
}
else {
if (func.applyAsBool(source)) {
kw.True(writer);
}
else {
kw.False(writer);
}
}
}
});
}
void addBool(final IteratorFunction iterator, final IterBoolFunction isNull, final IterBoolFunction func) {
iterate(iterator, isNull, new RenderIteration() {
@Override
public void render(AppendableByteWriter writer, T source, int i) {
if (func.applyAsBool(source, i)) {
kw.True(writer);
}
else {
kw.False(writer);
}
}});
}
void addBool(final ToBoolFunction isNull, final ToBoolFunction func, JSONType encode) {
switch (encode) {
case TypeString:
break;
case TypeInteger:
break;
case TypeDecimal:
break;
case TypeBoolean:
addBool(isNull, func);
break;
}
}
void addBool(IteratorFunction iterator, IterBoolFunction isNull, IterBoolFunction func, JSONType encode) {
switch (encode) {
case TypeString:
break;
case TypeInteger:
break;
case TypeDecimal:
break;
case TypeBoolean:
addBool(iterator, isNull, func);
break;
}
}
// Integer
void addInteger(final ToBoolFunction isNull, final ToLongFunction func) {
final byte[] declaredMemberName = consumeDeclaredMemberName();
scripts.add(new StringTemplateScript() {
@Override
public void render(AppendableByteWriter writer, T source) {
prefixObjectMemberName(declaredMemberName, depth, writer);
if (isNull != null && isNull.applyAsBool(source)) {
kw.Null(writer);
}
else {
Appendables.appendValue(writer, func.applyAsLong(source), false);
}
}
});
}
void addInteger(final IteratorFunction iterator, final IterBoolFunction isNull, final IterLongFunction func) {
iterate(iterator, isNull, new RenderIteration() {
@Override
public void render(AppendableByteWriter writer, T source, int i) {
Appendables.appendValue(writer, func.applyAsLong(source, i), false);
}});
}
void addInteger(ToBoolFunction isNull, ToLongFunction func, JSONType encode) {
switch (encode) {
case TypeString:
break;
case TypeInteger:
addInteger(isNull, func);
break;
case TypeDecimal:
break;
case TypeBoolean:
break;
}
}
void addInteger(IteratorFunction iterator, IterBoolFunction isNull, IterLongFunction func, JSONType encode) {
switch (encode) {
case TypeString:
break;
case TypeInteger:
addInteger(iterator, isNull, func);
break;
case TypeDecimal:
break;
case TypeBoolean:
break;
}
}
// Decimal
void addDecimal(final int precision, final ToBoolFunction isNull, final ToDoubleFunction func) {
final byte[] declaredMemberName = consumeDeclaredMemberName();
scripts.add(new StringTemplateScript() {
@Override
public void render(final AppendableByteWriter writer, T source) {
prefixObjectMemberName(declaredMemberName, depth, writer);
if (isNull != null && isNull.applyAsBool(source)) {
kw.Null(writer);
}
else {
double v = func.applyAsDouble(source);
Appendables.appendDecimalValue(writer, (long) (v * PipeWriter.powd[64 + precision]), (byte) (precision * -1));
}
}
});
}
void addDecimal(final IteratorFunction iterator, final int precision, final IterBoolFunction isNull, final IterDoubleFunction func) {
iterate(iterator, isNull, new RenderIteration() {
@Override
public void render(AppendableByteWriter writer, T source, int i) {
double v = func.applyAsDouble(source, i);
Appendables.appendDecimalValue(writer, (long) (v * PipeWriter.powd[64 + precision]), (byte) (precision * -1));
}
});
}
void addDecimal(int precision, ToBoolFunction isNull, ToDoubleFunction func, JSONType encode) {
switch (encode) {
case TypeString:
break;
case TypeInteger:
break;
case TypeDecimal:
addDecimal(precision, isNull, func);
break;
case TypeBoolean:
break;
}
}
void addDecimal(IteratorFunction iterator, int precision, IterBoolFunction isNull, IterDoubleFunction func, JSONType encode) {
switch (encode) {
case TypeString:
break;
case TypeInteger:
break;
case TypeDecimal:
addDecimal(iterator, precision, isNull, func);
break;
case TypeBoolean:
break;
}
}
// String
void addString(final boolean checkNull, final ToStringFunction func) {
final byte[] declaredMemberName = consumeDeclaredMemberName();
scripts.add(new StringTemplateScript() {
NullableAppendableByteWriterWrapper nabww = new NullableAppendableByteWriterWrapper();
@Override
public void render(AppendableByteWriter writer, T source) {
prefixObjectMemberName(declaredMemberName, depth, writer);
if (!checkNull) {
kw.Quote(writer);
func.applyAsString(source, writer);
kw.Quote(writer);
} else {
nabww.externalWriter = writer;
nabww.wasNull = false;
nabww.needsQuote = true;
func.applyAsString(source, nabww);
if (!nabww.wasNull) {
kw.Quote(writer);
} else {
//Note we are already reset to the beginning.
kw.Null(writer);
}
}
}
});
}
void addString(final IteratorFunction iterator,final boolean checkNull, final IterStringFunction func) {
iterate(iterator, checkNull, new IterMemberFunction() {
@Override
public T get(T o, int i) {
return o;
}
}, new RenderIteration() {
NullableAppendableByteWriterWrapper nabww = new NullableAppendableByteWriterWrapper();
@Override
public void render(AppendableByteWriter writer, T o, int i) {
if (!checkNull) {
kw.Quote(writer);
func.applyAsString(o, i, writer);
kw.Quote(writer);
} else {
nabww.externalWriter = writer;
nabww.wasNull = false;
nabww.needsQuote = true;
func.applyAsString(o, i, nabww);
if (!nabww.wasNull) {
kw.Quote(writer);
} else {
//Note we are already reset to the beginning.
kw.Null(writer);
}
}
}
});
}
void addString(boolean checkNull, ToStringFunction func, JSONType encode) {
switch (encode) {
case TypeString:
addString(checkNull, func);
break;
case TypeInteger:
break;
case TypeDecimal:
break;
case TypeBoolean:
break;
}
}
void addString(IteratorFunction iterator, boolean checkNull, IterStringFunction func, JSONType encode) {
switch (encode) {
case TypeString:
addString(iterator, checkNull, func);
break;
case TypeInteger:
break;
case TypeDecimal:
break;
case TypeBoolean:
break;
}
}
// Enum
> void addEnumName(final ToEnumFunction func) {
addString(true, new ToStringFunction() {
@Override
public void applyAsString(T value, AppendableByteWriter> target) {
E v = func.applyAsEnum(value);
if (null!=v) {
target.append(v.name());
} else {
target.append(null);
}
}
});
}
> void addEnumName(final IteratorFunction iterator, final IterEnumFunction func) {
iterate(iterator, true, new IterMemberFunction() {
@Override
public CharSequence get(T o, int i) {
E v = func.applyAsEnum(o, i);
return (v != null ? v.name() : null);
}
}, new RenderIteration() {
@Override
public void render(AppendableByteWriter writer, CharSequence member, int i) {
kw.Quote(writer);
writer.append(member);
kw.Quote(writer);
}
});
}
> void addEnumOrdinal(final ToEnumFunction func) {
final byte[] declaredMemberName = consumeDeclaredMemberName();
scripts.add(new StringTemplateScript() {
@Override
public void render(AppendableByteWriter writer, T source) {
prefixObjectMemberName(declaredMemberName, depth, writer);
E v = func.applyAsEnum(source);
if (v == null) {
kw.Null(writer);
}
else {
Appendables.appendValue(writer, v.ordinal());
}
}
});
}
> void addEnumOrdinal(final IteratorFunction iterator, final IterEnumFunction func) {
iterate(iterator, true, new IterMemberFunction() {
@Override
public Enum get(T o, int i) {
return func.applyAsEnum(o, i);
}
}, new RenderIteration() {
@Override
public void render(AppendableByteWriter writer, Enum member, int i) {
Appendables.appendValue(writer, member.ordinal());
}
});
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy