Skip to content

Commit

Permalink
trying to make basic functionality to intercept writes to json via an…
Browse files Browse the repository at this point in the history
… attached policy on the writer
  • Loading branch information
Mike Skells committed Sep 10, 2024
1 parent eb6d894 commit 93e4f14
Show file tree
Hide file tree
Showing 19 changed files with 1,950 additions and 1,567 deletions.
33 changes: 33 additions & 0 deletions library/src/main/java/com/dslplatform/json/ClassInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.dslplatform.json;

import java.util.List;

public class ClassInfo<C> {
private final Class<C> type;
private final CompiledJson.ObjectFormatPolicy objectFormatPolicy;
private final List<PropertyInfo> propertyInfos;
private final PropertyAccessor<C> propertyAccessor;

public ClassInfo(Class<C> type, CompiledJson.ObjectFormatPolicy objectFormatPolicy, List<PropertyInfo> propertyInfos, PropertyAccessor<C> propertyAccessor) {
this.type = type;
this.objectFormatPolicy = objectFormatPolicy;
this.propertyInfos = propertyInfos;
this.propertyAccessor = propertyAccessor;
}

public Class<C> getType() {
return type;
}

public CompiledJson.ObjectFormatPolicy getObjectFormatPolicy() {
return objectFormatPolicy;
}

public List<PropertyInfo> getPropertyInfos() {
return propertyInfos;
}

public PropertyAccessor<C> getPropertyAccessor() {
return propertyAccessor;
}
}
4 changes: 4 additions & 0 deletions library/src/main/java/com/dslplatform/json/ControlInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.dslplatform.json;

public abstract class ControlInfo{
}
60 changes: 35 additions & 25 deletions library/src/main/java/com/dslplatform/json/DslJson.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.sql.ResultSet;
import java.util.*;
Expand Down Expand Up @@ -73,7 +72,7 @@ public class DslJson<TContext> implements UnknownSerializer, TypeLookup {
* which can be reconstructed from schema information
*/
public final boolean omitDefaults;
public final boolean filterOutputs;
// public final boolean filterOutputs;
/**
* When object supports array format, eg. [prop1, prop2, prop3] this value must be enabled before
* object will be serialized in such a way. Regardless of this value deserialization will support all formats.
Expand All @@ -98,6 +97,7 @@ public class DslJson<TContext> implements UnknownSerializer, TypeLookup {
private final ExternalConverterAnalyzer externalConverterAnalyzer;
private final Map<Class<? extends Annotation>, Boolean> creatorMarkers;
private final JsonWriter.Factory writerFactory;
private final JsonControls controls;

public interface Fallback<TContext> {
void serialize(@Nullable Object instance, OutputStream stream) throws IOException;
Expand Down Expand Up @@ -125,7 +125,7 @@ public static class Settings<TContext> {
private TContext context;
private boolean javaSpecifics;
private Fallback<TContext> fallback;
private boolean omitDefaults;
//private boolean omitDefaults;
private boolean allowArrayFormat;
private StringCache keyCache = new SimpleStringCache();
private StringCache valuesCache;
Expand All @@ -142,7 +142,7 @@ public static class Settings<TContext> {
private final Set<ClassLoader> classLoaders = new HashSet<ClassLoader>();
private final Map<Class<? extends Annotation>, Boolean> creatorMarkers = new HashMap<Class<? extends Annotation>, Boolean>();
private JsonWriter.Factory writerFactory = new JsonWriter.Factory();
private boolean filterOutputs = false;
private JsonControls<? extends ControlInfo> controls = null;

/**
* Pass in context for DslJson.
Expand Down Expand Up @@ -189,8 +189,7 @@ public Settings<TContext> fallbackTo(@Nullable Fallback<TContext> fallback) {
* @return itself
*/
public Settings<TContext> skipDefaultValues(boolean omitDefaults) {
this.omitDefaults = omitDefaults;
return this;
return withControls(omitDefaults ? MinimalControls.INSTANCE : null);
}

/**
Expand Down Expand Up @@ -420,23 +419,33 @@ public Settings<TContext> creatorMarker(Class<? extends Annotation> marker, bool
this.creatorMarkers.put(marker, expandVisibility);
return this;
}
//
// /**
// * Set the custom writer factory to use
// * @return itself
// */
// public Settings<TContext> writerFactory(JsonWriter.Factory writerFactory) {
// if (writerFactory == null) throw new IllegalArgumentException("writerFactory can't be null");
// this.writerFactory = writerFactory;
// return this;
// }
//
// /**
// * Set if filtered outputs should be used
// * @return itself
// */
// public Settings<TContext> controlOutputs(boolean controlOutputs) {
// this.controlOutputs = controlOutputs;
// return this;
// }

/**
* Set the custom writer factory to use
* @return itself
*/
public Settings<TContext> writerFactory(JsonWriter.Factory writerFactory) {
if (writerFactory == null) throw new IllegalArgumentException("writerFactory can't be null");
this.writerFactory = writerFactory;
return this;
}

/**
* Set if filtered outputs should be used
* @return itself
*/
public Settings<TContext> filterOutputs(boolean filterOutputs) {
this.filterOutputs = filterOutputs;
public Settings<TContext> withControls(@Nullable JsonControls<? extends ControlInfo> controls) {
this.controls = controls;
return this;
}

Expand Down Expand Up @@ -516,7 +525,7 @@ public DslJson(final Settings<TContext> settings) {
this.localWriter = new ThreadLocal<JsonWriter>() {
@Override
protected JsonWriter initialValue() {
return writerFactory.create(4096, self);
return writerFactory.create(4096, self, controls);
}
};
this.localReader = new ThreadLocal<JsonReader>() {
Expand All @@ -527,7 +536,7 @@ protected JsonReader initialValue() {
};
this.context = settings.context;
this.fallback = settings.fallback;
this.omitDefaults = settings.omitDefaults;
this.omitDefaults = settings.controls != null;
this.allowArrayFormat = settings.allowArrayFormat;
this.keyCache = settings.keyCache;
this.valuesCache = settings.valuesCache;
Expand All @@ -545,7 +554,8 @@ protected JsonReader initialValue() {
this.externalConverterAnalyzer = new ExternalConverterAnalyzer(settings.classLoaders);
this.creatorMarkers = new HashMap<Class<? extends Annotation>, Boolean>(settings.creatorMarkers);
this.writerFactory = settings.writerFactory;
this.filterOutputs = settings.filterOutputs;
// this.filterOutputs = settings.controlOutputs;
this.controls = settings.controls;

BinaryConverter.registerDefault(this);
BoolConverter.registerDefault(this);
Expand Down Expand Up @@ -640,7 +650,7 @@ private String createAndPut(int index, char[] chars, int len) {
* @return bound writer
*/
public JsonWriter newWriter() {
return writerFactory.create(this);
return writerFactory.create(this, controls);
}

/**
Expand All @@ -653,7 +663,7 @@ public JsonWriter newWriter() {
* @return bound writer
*/
public JsonWriter newWriter(int size) {
return writerFactory.create(size, this);
return writerFactory.create(size, this, controls);
}

/**
Expand All @@ -667,7 +677,7 @@ public JsonWriter newWriter(int size) {
*/
public JsonWriter newWriter(byte[] buffer) {
if (buffer == null) throw new IllegalArgumentException("null value provided for buffer");
return writerFactory.create(buffer, this);
return writerFactory.create(buffer, this, controls);
}

/**
Expand Down Expand Up @@ -2410,7 +2420,7 @@ public <T> void iterateOver(
stream.write(JsonWriter.ARRAY_END);
return;
}
final JsonWriter buffer = writer == null ? writerFactory.create(this) : writer;
final JsonWriter buffer = writer == null ? writerFactory.create(this, this.controls) : writer;
T item = iterator.next();
Class<?> lastManifest = null;
JsonWriter.WriteObject lastWriter = null;
Expand Down Expand Up @@ -2486,7 +2496,7 @@ public <T> void iterateOver(
if (stream == null) {
throw new IllegalArgumentException("stream can't be null");
}
final JsonWriter buffer = writer == null ? writerFactory.create(this) : writer;
final JsonWriter buffer = writer == null ? writerFactory.create(this, this.controls) : writer;
final JsonWriter.WriteObject instanceWriter = getOrCreateWriter(null, manifest);
stream.write(JsonWriter.ARRAY_START);
T item = iterator.next();
Expand Down
23 changes: 23 additions & 0 deletions library/src/main/java/com/dslplatform/json/JsonAttributeInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.dslplatform.json;

import java.util.Arrays;
import java.util.List; /**
* Information captured from the annotation
*/
public final class JsonAttributeInfo {
public final String name;
public final int index;
public final List<String> alternativeNames;
public final boolean hasConverter;
public final JsonAttribute.IncludePolicy includeToMinimal;

public JsonAttributeInfo(String name,
int index, String[] alternativeNames, boolean hasConverter,
JsonAttribute.IncludePolicy includeToMinimal) {
this.name = name;
this.index = index;
this.alternativeNames = Arrays.asList(alternativeNames);
this.hasConverter = hasConverter;
this.includeToMinimal = includeToMinimal;
}
}
18 changes: 18 additions & 0 deletions library/src/main/java/com/dslplatform/json/JsonControls.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.dslplatform.json;

import java.util.List;

public abstract class JsonControls<T extends ControlInfo> {

protected JsonControls() {
}

public abstract <C> T controlledInfo(C instance, ClassInfo<C> classInfo);

public abstract <C> List<PropertyInfo> controlledProperties(C instance, ClassInfo<C> classInfo, T controlledInfo);


public abstract <C> PropertyWriteControl shouldWrite(C instance, ClassInfo<C> classInfo, T controlledInfo, PropertyInfo propertyInfo, JsonWriter writer, final Object value, final boolean checkDefaults, final boolean isNotDefaultValue);

public abstract <C> void afterPropertyWrite(C instance, ClassInfo<C> classInfo, T controlledInfo, PropertyInfo propertyInfo, JsonWriter writer, long positionBefore);
}
47 changes: 32 additions & 15 deletions library/src/main/java/com/dslplatform/json/JsonWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,22 @@
*/
public class JsonWriter {

public static class Factory {
public JsonControls<?> getControls() {
return controls;
}

public JsonWriter create(@Nullable final UnknownSerializer unknownSerializer) {
return new JsonWriter(unknownSerializer);
public static class Factory {

public JsonWriter create(@Nullable final UnknownSerializer unknownSerializer, JsonControls<?> controls) {
return new JsonWriter(unknownSerializer, controls);
}

public JsonWriter create(int size, @Nullable final UnknownSerializer unknownSerializer) {
return new JsonWriter(size, unknownSerializer);
public JsonWriter create(int size, @Nullable final UnknownSerializer unknownSerializer, JsonControls<?> controls) {
return new JsonWriter(size, unknownSerializer, controls);
}

public JsonWriter create(byte[] buffer, @Nullable final UnknownSerializer unknownSerializer) {
return new JsonWriter(buffer, unknownSerializer);
public JsonWriter create(byte[] buffer, @Nullable final UnknownSerializer unknownSerializer, JsonControls<?> controls) {
return new JsonWriter(buffer, unknownSerializer, controls);
}
}

Expand All @@ -60,20 +64,33 @@ void advance(int size) {
private byte[] buffer;

protected final UnknownSerializer unknownSerializer;
private final Grisu3.FastDtoaBuilder doubleBuilder = new Grisu3.FastDtoaBuilder();
private final JsonControls<?> controls;
private final Grisu3.FastDtoaBuilder doubleBuilder = new Grisu3.FastDtoaBuilder();

protected JsonWriter(@Nullable final UnknownSerializer unknownSerializer) {
this(512, unknownSerializer);
this(512, unknownSerializer, MinimalControls.INSTANCE);
}

protected JsonWriter(final int size, @Nullable final UnknownSerializer unknownSerializer) {
this(new byte[size], unknownSerializer);
this(new byte[size], unknownSerializer, MinimalControls.INSTANCE);
}

protected JsonWriter(final byte[] buffer, @Nullable final UnknownSerializer unknownSerializer) {
this(buffer, unknownSerializer, MinimalControls.INSTANCE);
}
public JsonWriter(@Nullable final UnknownSerializer unknownSerializer, JsonControls<?> controls) {
this(512, unknownSerializer, controls);
}

protected JsonWriter(final int size, @Nullable final UnknownSerializer unknownSerializer, JsonControls<?> controls) {
this(new byte[size], unknownSerializer, controls);
}

protected JsonWriter(final byte[] buffer, @Nullable final UnknownSerializer unknownSerializer, JsonControls<?> controls) {
this.buffer = buffer;
this.unknownSerializer = unknownSerializer;
}
this.controls = controls;
}

/**
* Helper for writing JSON object start: {
Expand Down Expand Up @@ -923,11 +940,11 @@ public void serializeObject(@Nullable final Object value) {
* @return some private memo used to call other filter methods later for this serialisation
* @param <C>
*/
public <C> FilterInfo controlledFilterInfo(C instance, Class<C> clazz, PropertyAccessor<C> access, List<PropertyInfo<C>> properties) {
public <C> FilterInfo controlledFilterInfo(C instance, Class<C> clazz, PropertyAccessor<C> access, List<PropertyInfo> properties) {
return FILTER_INFO_EMPTY;
}

public <C> List<PropertyInfo<C>> controlledStart(C instance, Class<C> clazz, PropertyAccessor<C> access, List<PropertyInfo<C>> properties, FilterInfo filterInfo) {
public <C> List<PropertyInfo> controlledStart(C instance, Class<C> clazz, PropertyAccessor<C> access, List<PropertyInfo> properties, FilterInfo filterInfo) {
return properties;
}

Expand All @@ -946,8 +963,8 @@ public <C> List<PropertyInfo<C>> controlledStart(C instance, Class<C> clazz, Pro
* @return null if the property should be skipped, or the writer to use for the property
* @param <C>
*/
public <C> @Nullable JsonWriter controlledPrepareForProperty(C instance, Class<C> clazz, PropertyAccessor<C> access, FilterInfo filterInfo, PropertyInfo<C> property, @Nullable JsonWriter writer) {
writeAscii(property.getQuoted());
public <C> @Nullable JsonWriter controlledPrepareForProperty(C instance, Class<C> clazz, PropertyAccessor<C> access, FilterInfo filterInfo, PropertyInfo property, @Nullable JsonWriter writer) {
// writeAscii(property.getQuoted());
return this;
}

Expand Down
40 changes: 40 additions & 0 deletions library/src/main/java/com/dslplatform/json/MinimalControls.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.dslplatform.json;

import java.util.List;

public class MinimalControls extends JsonControls<ControlInfo> {
public final static MinimalControls INSTANCE = new MinimalControls();
private final static ControlInfo NO_CONTROLS = new ControlInfo() {};

MinimalControls() {
}

public <C> ControlInfo controlledInfo(C instance, ClassInfo<C> classInfo) {
return NO_CONTROLS;
}

public <C> List<PropertyInfo> controlledProperties(C instance, ClassInfo<C> classInfo, ControlInfo controlledInfo) {
return classInfo.getPropertyInfos();
}


public <C> PropertyWriteControl shouldWrite(C instance, ClassInfo<C> classInfo, ControlInfo controlledInfo, PropertyInfo propertyInfo, JsonWriter writer, final Object value, final boolean checkDefaults, final boolean isNotDefaultValue) {
switch (classInfo.getObjectFormatPolicy()) {
case DEFAULT:
case EXPLICIT:
case CONTROLLED:
case MINIMAL:
return isNotDefaultValue ||
(propertyInfo.getAttribute().includeToMinimal == JsonAttribute.IncludePolicy.ALWAYS)
? PropertyWriteControl.WRITE_NORMALLY
: PropertyWriteControl.IGNORED;
case FULL:
return PropertyWriteControl.WRITE_NORMALLY;
default:
throw new IllegalArgumentException("Unsupported object format policy: " + classInfo.getObjectFormatPolicy());
}
}

public <C> void afterPropertyWrite(C instance, ClassInfo<C> classInfo, ControlInfo controlInfo, PropertyInfo propertyInfo, JsonWriter writer, long positionBefore) {
}
}
Loading

0 comments on commit 93e4f14

Please sign in to comment.