diff --git a/impl/src/main/java/org/eclipse/parsson/JsonArrayBuilderImpl.java b/impl/src/main/java/org/eclipse/parsson/JsonArrayBuilderImpl.java index 9bd99e4d..05eb4140 100644 --- a/impl/src/main/java/org/eclipse/parsson/JsonArrayBuilderImpl.java +++ b/impl/src/main/java/org/eclipse/parsson/JsonArrayBuilderImpl.java @@ -473,7 +473,7 @@ public int hashCode() { @Override public String toString() { StringWriter sw = new StringWriter(); - try (JsonWriter jw = new JsonWriterImpl(sw, bufferPool)) { + try (JsonWriter jw = new JsonWriterImpl(sw, bufferPool, Collections.emptyMap())) { jw.write(this); } return sw.toString(); diff --git a/impl/src/main/java/org/eclipse/parsson/JsonBuilderFactoryImpl.java b/impl/src/main/java/org/eclipse/parsson/JsonBuilderFactoryImpl.java index ff4a6a27..9bc879c9 100644 --- a/impl/src/main/java/org/eclipse/parsson/JsonBuilderFactoryImpl.java +++ b/impl/src/main/java/org/eclipse/parsson/JsonBuilderFactoryImpl.java @@ -17,15 +17,15 @@ package org.eclipse.parsson; import java.util.Collection; +import java.util.Map; + import org.eclipse.parsson.api.BufferPool; -import jakarta.json.JsonObject; import jakarta.json.JsonArray; import jakarta.json.JsonArrayBuilder; import jakarta.json.JsonBuilderFactory; +import jakarta.json.JsonObject; import jakarta.json.JsonObjectBuilder; -import java.util.Collections; -import java.util.Map; /** * @author Jitendra Kotamraju @@ -35,25 +35,25 @@ class JsonBuilderFactoryImpl implements JsonBuilderFactory { private final BufferPool bufferPool; private final boolean rejectDuplicateKeys; - JsonBuilderFactoryImpl(BufferPool bufferPool, boolean rejectDuplicateKeys) { - this.config = Collections.emptyMap(); + JsonBuilderFactoryImpl(BufferPool bufferPool, boolean rejectDuplicateKeys, Map config) { + this.config = config; this.bufferPool = bufferPool; this.rejectDuplicateKeys = rejectDuplicateKeys; } @Override public JsonObjectBuilder createObjectBuilder() { - return new JsonObjectBuilderImpl(bufferPool, rejectDuplicateKeys); + return new JsonObjectBuilderImpl(bufferPool, rejectDuplicateKeys, config); } @Override public JsonObjectBuilder createObjectBuilder(JsonObject object) { - return new JsonObjectBuilderImpl(object, bufferPool, rejectDuplicateKeys); + return new JsonObjectBuilderImpl(object, bufferPool, rejectDuplicateKeys, config); } @Override public JsonObjectBuilder createObjectBuilder(Map object) { - return new JsonObjectBuilderImpl(object, bufferPool, rejectDuplicateKeys); + return new JsonObjectBuilderImpl(object, bufferPool, rejectDuplicateKeys, config); } @Override diff --git a/impl/src/main/java/org/eclipse/parsson/JsonGeneratorFactoryImpl.java b/impl/src/main/java/org/eclipse/parsson/JsonGeneratorFactoryImpl.java index 00a54e8c..b50d5686 100644 --- a/impl/src/main/java/org/eclipse/parsson/JsonGeneratorFactoryImpl.java +++ b/impl/src/main/java/org/eclipse/parsson/JsonGeneratorFactoryImpl.java @@ -44,22 +44,22 @@ class JsonGeneratorFactoryImpl implements JsonGeneratorFactory { @Override public JsonGenerator createGenerator(Writer writer) { return prettyPrinting - ? new JsonPrettyGeneratorImpl(writer, bufferPool) - : new JsonGeneratorImpl(writer, bufferPool); + ? new JsonPrettyGeneratorImpl(writer, bufferPool, config) + : new JsonGeneratorImpl(writer, bufferPool, config); } @Override public JsonGenerator createGenerator(OutputStream out) { return prettyPrinting - ? new JsonPrettyGeneratorImpl(out, bufferPool) - : new JsonGeneratorImpl(out, bufferPool); + ? new JsonPrettyGeneratorImpl(out, bufferPool, config) + : new JsonGeneratorImpl(out, bufferPool, config); } @Override public JsonGenerator createGenerator(OutputStream out, Charset charset) { return prettyPrinting - ? new JsonPrettyGeneratorImpl(out, charset, bufferPool) - : new JsonGeneratorImpl(out, charset, bufferPool); + ? new JsonPrettyGeneratorImpl(out, charset, bufferPool, config) + : new JsonGeneratorImpl(out, charset, bufferPool, config); } @Override diff --git a/impl/src/main/java/org/eclipse/parsson/JsonGeneratorImpl.java b/impl/src/main/java/org/eclipse/parsson/JsonGeneratorImpl.java index 63fab88e..e6e4dd29 100644 --- a/impl/src/main/java/org/eclipse/parsson/JsonGeneratorImpl.java +++ b/impl/src/main/java/org/eclipse/parsson/JsonGeneratorImpl.java @@ -84,6 +84,7 @@ private static enum Scope { private final Writer writer; private Context currentContext = new Context(Scope.IN_NONE); private final Deque stack = new ArrayDeque<>(); + private final boolean ignoreNull; // Using own buffering mechanism as JDK's BufferedWriter uses synchronized // methods. Also, flushBuffer() is useful when you don't want to actually @@ -91,18 +92,19 @@ private static enum Scope { private final char buf[]; // capacity >= INT_MIN_VALUE_CHARS.length private int len = 0; - JsonGeneratorImpl(Writer writer, BufferPool bufferPool) { + JsonGeneratorImpl(Writer writer, BufferPool bufferPool, Map config) { this.writer = writer; + this.ignoreNull = JsonUtil.getConfigValue(JsonBuilderFactory.IGNORE_ADDING_IF_NULL, false, config); this.bufferPool = bufferPool; this.buf = bufferPool.take(); } - JsonGeneratorImpl(OutputStream out, BufferPool bufferPool) { - this(out, StandardCharsets.UTF_8, bufferPool); + JsonGeneratorImpl(OutputStream out, BufferPool bufferPool, Map config) { + this(out, StandardCharsets.UTF_8, bufferPool, config); } - JsonGeneratorImpl(OutputStream out, Charset encoding, BufferPool bufferPool) { - this(new OutputStreamWriter(out, encoding), bufferPool); + JsonGeneratorImpl(OutputStream out, Charset encoding, BufferPool bufferPool, Map config) { + this(new OutputStreamWriter(out, encoding), bufferPool, config); } @Override @@ -152,7 +154,9 @@ private JsonGenerator writeName(String name) { @Override public JsonGenerator write(String name, String fieldValue) { - write(name, (CharSequence) fieldValue); + if (validateNull(fieldValue)) { + write(name, (CharSequence) fieldValue); + } return this; } @@ -194,23 +198,27 @@ public JsonGenerator write(String name, double value) { @Override public JsonGenerator write(String name, BigInteger value) { - if (currentContext.scope != Scope.IN_OBJECT) { - throw new JsonGenerationException( - JsonMessages.GENERATOR_ILLEGAL_METHOD(currentContext.scope)); + if (validateNull(value)) { + if (currentContext.scope != Scope.IN_OBJECT) { + throw new JsonGenerationException( + JsonMessages.GENERATOR_ILLEGAL_METHOD(currentContext.scope)); + } + writeName(name); + writeString(String.valueOf(value)); } - writeName(name); - writeString(String.valueOf(value)); return this; } @Override public JsonGenerator write(String name, BigDecimal value) { - if (currentContext.scope != Scope.IN_OBJECT) { - throw new JsonGenerationException( - JsonMessages.GENERATOR_ILLEGAL_METHOD(currentContext.scope)); + if (validateNull(value)) { + if (currentContext.scope != Scope.IN_OBJECT) { + throw new JsonGenerationException( + JsonMessages.GENERATOR_ILLEGAL_METHOD(currentContext.scope)); + } + writeName(name); + writeString(String.valueOf(value)); } - writeName(name); - writeString(String.valueOf(value)); return this; } @@ -238,45 +246,46 @@ public JsonGenerator writeNull(String name) { @Override public JsonGenerator write(JsonValue value) { - checkContextForValue(); - - switch (value.getValueType()) { - case ARRAY: - JsonArray array = (JsonArray)value; - writeStartArray(); - for(JsonValue child: array) { - write(child); - } - writeEnd(); - break; - case OBJECT: - JsonObject object = (JsonObject)value; - writeStartObject(); - for(Map.Entry member: object.entrySet()) { - write(member.getKey(), member.getValue()); - } - writeEnd(); - break; - case STRING: - JsonString str = (JsonString)value; - write(str.getString()); - break; - case NUMBER: - JsonNumber number = (JsonNumber)value; - writeValue(number.toString()); - popFieldContext(); - break; - case TRUE: - write(true); - break; - case FALSE: - write(false); - break; - case NULL: - writeNull(); - break; + if (validateNull(value)) { + checkContextForValue(); + + switch (value.getValueType()) { + case ARRAY: + JsonArray array = (JsonArray)value; + writeStartArray(); + for(JsonValue child: array) { + write(child); + } + writeEnd(); + break; + case OBJECT: + JsonObject object = (JsonObject)value; + writeStartObject(); + for(Map.Entry member: object.entrySet()) { + write(member.getKey(), member.getValue()); + } + writeEnd(); + break; + case STRING: + JsonString str = (JsonString)value; + write(str.getString()); + break; + case NUMBER: + JsonNumber number = (JsonNumber)value; + writeValue(number.toString()); + popFieldContext(); + break; + case TRUE: + write(true); + break; + case FALSE: + write(false); + break; + case NULL: + writeNull(); + break; + } } - return this; } @@ -310,54 +319,58 @@ public JsonGenerator writeStartArray(String name) { @Override public JsonGenerator write(String name, JsonValue value) { - if (currentContext.scope != Scope.IN_OBJECT) { - throw new JsonGenerationException( - JsonMessages.GENERATOR_ILLEGAL_METHOD(currentContext.scope)); - } - switch (value.getValueType()) { - case ARRAY: - JsonArray array = (JsonArray)value; - writeStartArray(name); - for(JsonValue child: array) { - write(child); - } - writeEnd(); - break; - case OBJECT: - JsonObject object = (JsonObject)value; - writeStartObject(name); - for(Map.Entry member: object.entrySet()) { - write(member.getKey(), member.getValue()); - } - writeEnd(); - break; - case STRING: - JsonString str = (JsonString)value; - write(name, str.getChars()); - break; - case NUMBER: - JsonNumber number = (JsonNumber)value; - writeValue(name, number.toString()); - break; - case TRUE: - write(name, true); - break; - case FALSE: - write(name, false); - break; - case NULL: - writeNull(name); - break; + if (validateNull(value)) { + if (currentContext.scope != Scope.IN_OBJECT) { + throw new JsonGenerationException( + JsonMessages.GENERATOR_ILLEGAL_METHOD(currentContext.scope)); + } + switch (value.getValueType()) { + case ARRAY: + JsonArray array = (JsonArray)value; + writeStartArray(name); + for(JsonValue child: array) { + write(child); + } + writeEnd(); + break; + case OBJECT: + JsonObject object = (JsonObject)value; + writeStartObject(name); + for(Map.Entry member: object.entrySet()) { + write(member.getKey(), member.getValue()); + } + writeEnd(); + break; + case STRING: + JsonString str = (JsonString)value; + write(name, str.getChars()); + break; + case NUMBER: + JsonNumber number = (JsonNumber)value; + writeValue(name, number.toString()); + break; + case TRUE: + write(name, true); + break; + case FALSE: + write(name, false); + break; + case NULL: + writeNull(name); + break; + } } return this; } @Override public JsonGenerator write(String value) { - checkContextForValue(); - writeComma(); - writeEscapedString(value); - popFieldContext(); + if (validateNull(value)) { + checkContextForValue(); + writeComma(); + writeEscapedString(value); + popFieldContext(); + } return this; } @@ -392,9 +405,11 @@ public JsonGenerator write(double value) { @Override public JsonGenerator write(BigInteger value) { - checkContextForValue(); - writeValue(value.toString()); - popFieldContext(); + if (validateNull(value)) { + checkContextForValue(); + writeValue(value.toString()); + popFieldContext(); + } return this; } @@ -408,10 +423,11 @@ private void checkContextForValue() { @Override public JsonGenerator write(BigDecimal value) { - checkContextForValue(); - writeValue(value.toString()); - popFieldContext(); - + if (validateNull(value)) { + checkContextForValue(); + writeValue(value.toString()); + popFieldContext(); + } return this; } @@ -440,15 +456,19 @@ public JsonGenerator writeNull() { } private void writeValue(String value) { - writeComma(); - writeString(value); + if (validateNull(value)) { + writeComma(); + writeString(value); + } } private void writeValue(String name, String value) { - writeComma(); - writeEscapedString(name); - writeColon(); - writeString(value); + if (validateNull(value)) { + writeComma(); + writeEscapedString(name); + writeColon(); + writeString(value); + } } @Override @@ -476,12 +496,14 @@ public JsonGenerator writeEnd() { } void write(String name, CharSequence fieldValue) { - if (currentContext.scope != Scope.IN_OBJECT) { - throw new JsonGenerationException( - JsonMessages.GENERATOR_ILLEGAL_METHOD(currentContext.scope)); - } - writeName(name); - writeEscapedString(fieldValue); + if (validateNull(fieldValue)) { + if (currentContext.scope != Scope.IN_OBJECT) { + throw new JsonGenerationException( + JsonMessages.GENERATOR_ILLEGAL_METHOD(currentContext.scope)); + } + writeName(name); + writeEscapedString(fieldValue); + } } protected void writeComma() { @@ -730,4 +752,7 @@ private static void fillIntChars(int i, char[] buf, int index) { } } + private boolean validateNull(Object value) { + return (!ignoreNull || (ignoreNull && value != null)); + } } diff --git a/impl/src/main/java/org/eclipse/parsson/JsonObjectBuilderImpl.java b/impl/src/main/java/org/eclipse/parsson/JsonObjectBuilderImpl.java index 43619d4e..c13d88ce 100644 --- a/impl/src/main/java/org/eclipse/parsson/JsonObjectBuilderImpl.java +++ b/impl/src/main/java/org/eclipse/parsson/JsonObjectBuilderImpl.java @@ -34,15 +34,18 @@ class JsonObjectBuilderImpl implements JsonObjectBuilder { protected Map valueMap; private final BufferPool bufferPool; + private final boolean ignoreNull; private final boolean rejectDuplicateKeys; JsonObjectBuilderImpl(BufferPool bufferPool) { this.bufferPool = bufferPool; + this.ignoreNull = false; rejectDuplicateKeys = false; } - JsonObjectBuilderImpl(BufferPool bufferPool, boolean rejectDuplicateKeys) { + JsonObjectBuilderImpl(BufferPool bufferPool, boolean rejectDuplicateKeys, Map config) { this.bufferPool = bufferPool; + this.ignoreNull = JsonUtil.getConfigValue(JsonBuilderFactory.IGNORE_ADDING_IF_NULL, false, config); this.rejectDuplicateKeys = rejectDuplicateKeys; } @@ -50,13 +53,15 @@ class JsonObjectBuilderImpl implements JsonObjectBuilder { this.bufferPool = bufferPool; valueMap = new LinkedHashMap<>(); valueMap.putAll(object); + this.ignoreNull = false; rejectDuplicateKeys = false; } - JsonObjectBuilderImpl(JsonObject object, BufferPool bufferPool, boolean rejectDuplicateKeys) { + JsonObjectBuilderImpl(JsonObject object, BufferPool bufferPool, boolean rejectDuplicateKeys, Map config) { this.bufferPool = bufferPool; valueMap = new LinkedHashMap<>(); valueMap.putAll(object); + this.ignoreNull = JsonUtil.getConfigValue(JsonBuilderFactory.IGNORE_ADDING_IF_NULL, false, config); this.rejectDuplicateKeys = rejectDuplicateKeys; } @@ -64,45 +69,51 @@ class JsonObjectBuilderImpl implements JsonObjectBuilder { this.bufferPool = bufferPool; valueMap = new LinkedHashMap<>(); populate(map); + this.ignoreNull = false; rejectDuplicateKeys = false; } - JsonObjectBuilderImpl(Map map, BufferPool bufferPool, boolean rejectDuplicateKeys) { + JsonObjectBuilderImpl(Map map, BufferPool bufferPool, boolean rejectDuplicateKeys, Map config) { this.bufferPool = bufferPool; valueMap = new LinkedHashMap<>(); populate(map); + this.ignoreNull = JsonUtil.getConfigValue(JsonBuilderFactory.IGNORE_ADDING_IF_NULL, false, config); this.rejectDuplicateKeys = rejectDuplicateKeys; } @Override public JsonObjectBuilder add(String name, JsonValue value) { validateName(name); - validateValue(value); - putValueMap(name, value); + if (validateValue(value)) { + putValueMap(name, value); + } return this; } @Override public JsonObjectBuilder add(String name, String value) { validateName(name); - validateValue(value); - putValueMap(name, new JsonStringImpl(value)); + if (validateValue(value)) { + putValueMap(name, new JsonStringImpl(value)); + } return this; } @Override public JsonObjectBuilder add(String name, BigInteger value) { validateName(name); - validateValue(value); - putValueMap(name, JsonNumberImpl.getJsonNumber(value)); + if (validateValue(value)) { + putValueMap(name, JsonNumberImpl.getJsonNumber(value)); + } return this; } @Override public JsonObjectBuilder add(String name, BigDecimal value) { validateName(name); - validateValue(value); - putValueMap(name, JsonNumberImpl.getJsonNumber(value)); + if (validateValue(value)) { + putValueMap(name, JsonNumberImpl.getJsonNumber(value)); + } return this; } @@ -218,10 +229,15 @@ private void validateName(String name) { } } - private void validateValue(Object value) { + private boolean validateValue(Object value) { if (value == null) { - throw new NullPointerException(JsonMessages.OBJBUILDER_VALUE_NULL()); + if (ignoreNull) { + return false; + } else { + throw new NullPointerException(JsonMessages.OBJBUILDER_VALUE_NULL()); + } } + return true; } private static final class JsonObjectImpl extends AbstractMap implements JsonObject { @@ -336,7 +352,7 @@ public int hashCode() { @Override public String toString() { StringWriter sw = new StringWriter(); - try (JsonWriter jw = new JsonWriterImpl(sw, bufferPool)) { + try (JsonWriter jw = new JsonWriterImpl(sw, bufferPool, Collections.emptyMap())) { jw.write(this); } return sw.toString(); diff --git a/impl/src/main/java/org/eclipse/parsson/JsonParserImpl.java b/impl/src/main/java/org/eclipse/parsson/JsonParserImpl.java index 75983f37..18c4aef7 100644 --- a/impl/src/main/java/org/eclipse/parsson/JsonParserImpl.java +++ b/impl/src/main/java/org/eclipse/parsson/JsonParserImpl.java @@ -23,6 +23,7 @@ import java.math.BigDecimal; import java.nio.charset.Charset; import java.util.AbstractMap; +import java.util.Collections; import java.util.Map; import java.util.NoSuchElementException; import java.util.Spliterator; @@ -55,6 +56,7 @@ public class JsonParserImpl implements JsonParser { private final BufferPool bufferPool; private final boolean rejectDuplicateKeys; + private final Map config; private Context currentContext = new NoneContext(); private Event currentEvent; @@ -63,33 +65,36 @@ public class JsonParserImpl implements JsonParser { private boolean closed = false; public JsonParserImpl(Reader reader, BufferPool bufferPool) { - this(reader, bufferPool, false); + this(reader, bufferPool, false, Collections.emptyMap()); } - public JsonParserImpl(Reader reader, BufferPool bufferPool, boolean rejectDuplicateKeys) { + public JsonParserImpl(Reader reader, BufferPool bufferPool, boolean rejectDuplicateKeys, Map config) { this.bufferPool = bufferPool; this.rejectDuplicateKeys = rejectDuplicateKeys; + this.config = config; tokenizer = new JsonTokenizer(reader, bufferPool); } public JsonParserImpl(InputStream in, BufferPool bufferPool) { - this(in, bufferPool, false); + this(in, bufferPool, false, Collections.emptyMap()); } - public JsonParserImpl(InputStream in, BufferPool bufferPool, boolean rejectDuplicateKeys) { + public JsonParserImpl(InputStream in, BufferPool bufferPool, boolean rejectDuplicateKeys, Map config) { this.bufferPool = bufferPool; this.rejectDuplicateKeys = rejectDuplicateKeys; + this.config = config; UnicodeDetectingInputStream uin = new UnicodeDetectingInputStream(in); tokenizer = new JsonTokenizer(new InputStreamReader(uin, uin.getCharset()), bufferPool); } public JsonParserImpl(InputStream in, Charset encoding, BufferPool bufferPool) { - this(in, encoding, bufferPool, false); + this(in, encoding, bufferPool, false, Collections.emptyMap()); } - public JsonParserImpl(InputStream in, Charset encoding, BufferPool bufferPool, boolean rejectDuplicateKeys) { + public JsonParserImpl(InputStream in, Charset encoding, BufferPool bufferPool, boolean rejectDuplicateKeys, Map config) { this.bufferPool = bufferPool; this.rejectDuplicateKeys = rejectDuplicateKeys; + this.config = config; tokenizer = new JsonTokenizer(new InputStreamReader(in, encoding), bufferPool); } @@ -162,7 +167,7 @@ public JsonObject getObject() { throw new IllegalStateException( JsonMessages.PARSER_GETOBJECT_ERR(currentEvent)); } - return getObject(new JsonObjectBuilderImpl(bufferPool, rejectDuplicateKeys)); + return getObject(new JsonObjectBuilderImpl(bufferPool, rejectDuplicateKeys, config)); } @Override @@ -171,7 +176,7 @@ public JsonValue getValue() { case START_ARRAY: return getArray(new JsonArrayBuilderImpl(bufferPool)); case START_OBJECT: - return getObject(new JsonObjectBuilderImpl(bufferPool, rejectDuplicateKeys)); + return getObject(new JsonObjectBuilderImpl(bufferPool, rejectDuplicateKeys, config)); case KEY_NAME: case VALUE_STRING: return new JsonStringImpl(getCharSequence()); diff --git a/impl/src/main/java/org/eclipse/parsson/JsonPrettyGeneratorImpl.java b/impl/src/main/java/org/eclipse/parsson/JsonPrettyGeneratorImpl.java index 82d8de6b..53a06a9d 100644 --- a/impl/src/main/java/org/eclipse/parsson/JsonPrettyGeneratorImpl.java +++ b/impl/src/main/java/org/eclipse/parsson/JsonPrettyGeneratorImpl.java @@ -22,24 +22,25 @@ import java.io.OutputStream; import java.io.Writer; import java.nio.charset.Charset; +import java.util.Map; /** * @author Jitendra Kotamraju */ -public class JsonPrettyGeneratorImpl extends JsonGeneratorImpl { +class JsonPrettyGeneratorImpl extends JsonGeneratorImpl { private int indentLevel; private static final String INDENT = " "; - public JsonPrettyGeneratorImpl(Writer writer, BufferPool bufferPool) { - super(writer, bufferPool); + JsonPrettyGeneratorImpl(Writer writer, BufferPool bufferPool, Map config) { + super(writer, bufferPool, config); } - public JsonPrettyGeneratorImpl(OutputStream out, BufferPool bufferPool) { - super(out, bufferPool); + JsonPrettyGeneratorImpl(OutputStream out, BufferPool bufferPool, Map config) { + super(out, bufferPool, config); } - public JsonPrettyGeneratorImpl(OutputStream out, Charset encoding, BufferPool bufferPool) { - super(out, encoding, bufferPool); + JsonPrettyGeneratorImpl(OutputStream out, Charset encoding, BufferPool bufferPool, Map config) { + super(out, encoding, bufferPool, config); } @Override diff --git a/impl/src/main/java/org/eclipse/parsson/JsonProviderImpl.java b/impl/src/main/java/org/eclipse/parsson/JsonProviderImpl.java index 05ca3048..fbacdb81 100644 --- a/impl/src/main/java/org/eclipse/parsson/JsonProviderImpl.java +++ b/impl/src/main/java/org/eclipse/parsson/JsonProviderImpl.java @@ -46,12 +46,12 @@ public class JsonProviderImpl extends JsonProvider { @Override public JsonGenerator createGenerator(Writer writer) { - return new JsonGeneratorImpl(writer, bufferPool); + return new JsonGeneratorImpl(writer, bufferPool, Collections.emptyMap()); } @Override public JsonGenerator createGenerator(OutputStream out) { - return new JsonGeneratorImpl(out, bufferPool); + return new JsonGeneratorImpl(out, bufferPool, Collections.emptyMap()); } @Override @@ -96,6 +96,7 @@ public JsonGeneratorFactory createGeneratorFactory(Map config) { } else { pool = bufferPool; } + addKnowProperty(providerConfig, config, JsonBuilderFactory.IGNORE_ADDING_IF_NULL); providerConfig = Collections.unmodifiableMap(providerConfig); } @@ -114,12 +115,12 @@ public JsonReader createReader(InputStream in) { @Override public JsonWriter createWriter(Writer writer) { - return new JsonWriterImpl(writer, bufferPool); + return new JsonWriterImpl(writer, bufferPool, Collections.emptyMap()); } @Override public JsonWriter createWriter(OutputStream out) { - return new JsonWriterImpl(out, bufferPool); + return new JsonWriterImpl(out, bufferPool, Collections.emptyMap()); } @Override @@ -269,15 +270,25 @@ public JsonNumber createValue(BigDecimal value) { @Override public JsonBuilderFactory createBuilderFactory(Map config) { + Map providerConfig = Collections.emptyMap(); BufferPool pool = bufferPool; boolean rejectDuplicateKeys = false; if (config != null) { + providerConfig = new HashMap<>(); if (config.containsKey(BufferPool.class.getName())) { pool = (BufferPool) config.get(BufferPool.class.getName()); } rejectDuplicateKeys = JsonProviderImpl.isRejectDuplicateKeysEnabled(config); + addKnowProperty(providerConfig, config, JsonBuilderFactory.IGNORE_ADDING_IF_NULL); + providerConfig = Collections.unmodifiableMap(providerConfig); } - return new JsonBuilderFactoryImpl(pool, rejectDuplicateKeys); + return new JsonBuilderFactoryImpl(pool, rejectDuplicateKeys, providerConfig); + } + + private void addKnowProperty(Map providerConfig, Map config, String property) { + if (config.containsKey(property)) { + providerConfig.put(property, config.get(property)); + } } static boolean isPrettyPrintingEnabled(Map config) { diff --git a/impl/src/main/java/org/eclipse/parsson/JsonReaderFactoryImpl.java b/impl/src/main/java/org/eclipse/parsson/JsonReaderFactoryImpl.java index ea896746..1561d704 100644 --- a/impl/src/main/java/org/eclipse/parsson/JsonReaderFactoryImpl.java +++ b/impl/src/main/java/org/eclipse/parsson/JsonReaderFactoryImpl.java @@ -16,15 +16,16 @@ package org.eclipse.parsson; -import org.eclipse.parsson.api.BufferPool; - -import jakarta.json.JsonReader; -import jakarta.json.JsonReaderFactory; import java.io.InputStream; import java.io.Reader; import java.nio.charset.Charset; import java.util.Map; +import org.eclipse.parsson.api.BufferPool; + +import jakarta.json.JsonReader; +import jakarta.json.JsonReaderFactory; + /** * @author Jitendra Kotamraju */ @@ -41,17 +42,17 @@ class JsonReaderFactoryImpl implements JsonReaderFactory { @Override public JsonReader createReader(Reader reader) { - return new JsonReaderImpl(reader, bufferPool, rejectDuplicateKeys); + return new JsonReaderImpl(reader, bufferPool, rejectDuplicateKeys, config); } @Override public JsonReader createReader(InputStream in) { - return new JsonReaderImpl(in, bufferPool, rejectDuplicateKeys); + return new JsonReaderImpl(in, bufferPool, rejectDuplicateKeys, config); } @Override public JsonReader createReader(InputStream in, Charset charset) { - return new JsonReaderImpl(in, charset, bufferPool, rejectDuplicateKeys); + return new JsonReaderImpl(in, charset, bufferPool, rejectDuplicateKeys, config); } @Override diff --git a/impl/src/main/java/org/eclipse/parsson/JsonReaderImpl.java b/impl/src/main/java/org/eclipse/parsson/JsonReaderImpl.java index 78dc6ecf..d41999bd 100644 --- a/impl/src/main/java/org/eclipse/parsson/JsonReaderImpl.java +++ b/impl/src/main/java/org/eclipse/parsson/JsonReaderImpl.java @@ -21,6 +21,9 @@ import java.io.InputStream; import java.io.Reader; import java.nio.charset.Charset; +import java.util.Collections; +import java.util.Map; + import jakarta.json.JsonArray; import jakarta.json.JsonException; import jakarta.json.JsonObject; @@ -41,29 +44,29 @@ class JsonReaderImpl implements JsonReader { private final BufferPool bufferPool; JsonReaderImpl(Reader reader, BufferPool bufferPool) { - this(reader, bufferPool, false); + this(reader, bufferPool, false, Collections.emptyMap()); } - JsonReaderImpl(Reader reader, BufferPool bufferPool, boolean rejectDuplicateKeys) { - parser = new JsonParserImpl(reader, bufferPool, rejectDuplicateKeys); + JsonReaderImpl(Reader reader, BufferPool bufferPool, boolean rejectDuplicateKeys, Map config) { + parser = new JsonParserImpl(reader, bufferPool, rejectDuplicateKeys, config); this.bufferPool = bufferPool; } JsonReaderImpl(InputStream in, BufferPool bufferPool) { - this(in, bufferPool, false); + this(in, bufferPool, false, Collections.emptyMap()); } - JsonReaderImpl(InputStream in, BufferPool bufferPool, boolean rejectDuplicateKeys) { - parser = new JsonParserImpl(in, bufferPool, rejectDuplicateKeys); + JsonReaderImpl(InputStream in, BufferPool bufferPool, boolean rejectDuplicateKeys, Map config) { + parser = new JsonParserImpl(in, bufferPool, rejectDuplicateKeys, config); this.bufferPool = bufferPool; } JsonReaderImpl(InputStream in, Charset charset, BufferPool bufferPool) { - this(in, charset, bufferPool, false); + this(in, charset, bufferPool, false, Collections.emptyMap()); } - JsonReaderImpl(InputStream in, Charset charset, BufferPool bufferPool, boolean rejectDuplicateKeys) { - parser = new JsonParserImpl(in, charset, bufferPool, rejectDuplicateKeys); + JsonReaderImpl(InputStream in, Charset charset, BufferPool bufferPool, boolean rejectDuplicateKeys, Map config) { + parser = new JsonParserImpl(in, charset, bufferPool, rejectDuplicateKeys, config); this.bufferPool = bufferPool; } diff --git a/impl/src/main/java/org/eclipse/parsson/JsonUtil.java b/impl/src/main/java/org/eclipse/parsson/JsonUtil.java index 747ba803..574fe4f6 100644 --- a/impl/src/main/java/org/eclipse/parsson/JsonUtil.java +++ b/impl/src/main/java/org/eclipse/parsson/JsonUtil.java @@ -17,6 +17,8 @@ package org.eclipse.parsson; import java.io.StringReader; +import java.util.Map; + import jakarta.json.JsonReader; import jakarta.json.JsonValue; import jakarta.json.stream.JsonParsingException; @@ -81,5 +83,14 @@ public static JsonValue toJson(String jsonString) { reader.close(); return value; } + + static boolean getConfigValue(String key, boolean defaultValue, Map config) { + Object value = config.get(key); + if (value instanceof Boolean) { + return (boolean) value; + } + return defaultValue; + } + } diff --git a/impl/src/main/java/org/eclipse/parsson/JsonWriterFactoryImpl.java b/impl/src/main/java/org/eclipse/parsson/JsonWriterFactoryImpl.java index 96fd42c4..1af5e736 100644 --- a/impl/src/main/java/org/eclipse/parsson/JsonWriterFactoryImpl.java +++ b/impl/src/main/java/org/eclipse/parsson/JsonWriterFactoryImpl.java @@ -42,17 +42,17 @@ class JsonWriterFactoryImpl implements JsonWriterFactory { @Override public JsonWriter createWriter(Writer writer) { - return new JsonWriterImpl(writer, prettyPrinting, bufferPool); + return new JsonWriterImpl(writer, prettyPrinting, bufferPool, config); } @Override public JsonWriter createWriter(OutputStream out) { - return new JsonWriterImpl(out, prettyPrinting, bufferPool); + return new JsonWriterImpl(out, prettyPrinting, bufferPool, config); } @Override public JsonWriter createWriter(OutputStream out, Charset charset) { - return new JsonWriterImpl(out, charset, prettyPrinting, bufferPool); + return new JsonWriterImpl(out, charset, prettyPrinting, bufferPool, config); } @Override diff --git a/impl/src/main/java/org/eclipse/parsson/JsonWriterImpl.java b/impl/src/main/java/org/eclipse/parsson/JsonWriterImpl.java index 57b41556..38665cef 100644 --- a/impl/src/main/java/org/eclipse/parsson/JsonWriterImpl.java +++ b/impl/src/main/java/org/eclipse/parsson/JsonWriterImpl.java @@ -16,9 +16,6 @@ package org.eclipse.parsson; -import org.eclipse.parsson.api.BufferPool; - -import jakarta.json.*; import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; @@ -27,6 +24,14 @@ import java.nio.charset.StandardCharsets; import java.util.Map; +import org.eclipse.parsson.api.BufferPool; + +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.json.JsonStructure; +import jakarta.json.JsonValue; +import jakarta.json.JsonWriter; + /** * JsonWriter impl using generator. * @@ -38,33 +43,33 @@ class JsonWriterImpl implements JsonWriter { private boolean writeDone; private final NoFlushOutputStream os; - JsonWriterImpl(Writer writer, BufferPool bufferPool) { - this(writer, false, bufferPool); + JsonWriterImpl(Writer writer, BufferPool bufferPool, Map config) { + this(writer, false, bufferPool, config); } - JsonWriterImpl(Writer writer, boolean prettyPrinting, BufferPool bufferPool) { + JsonWriterImpl(Writer writer, boolean prettyPrinting, BufferPool bufferPool, Map config) { generator = prettyPrinting - ? new JsonPrettyGeneratorImpl(writer, bufferPool) - : new JsonGeneratorImpl(writer, bufferPool); + ? new JsonPrettyGeneratorImpl(writer, bufferPool, config) + : new JsonGeneratorImpl(writer, bufferPool, config); os = null; } - JsonWriterImpl(OutputStream out, BufferPool bufferPool) { - this(out, StandardCharsets.UTF_8, false, bufferPool); + JsonWriterImpl(OutputStream out, BufferPool bufferPool, Map config) { + this(out, StandardCharsets.UTF_8, false, bufferPool, config); } - JsonWriterImpl(OutputStream out, boolean prettyPrinting, BufferPool bufferPool) { - this(out, StandardCharsets.UTF_8, prettyPrinting, bufferPool); + JsonWriterImpl(OutputStream out, boolean prettyPrinting, BufferPool bufferPool, Map config) { + this(out, StandardCharsets.UTF_8, prettyPrinting, bufferPool, config); } JsonWriterImpl(OutputStream out, Charset charset, - boolean prettyPrinting, BufferPool bufferPool) { + boolean prettyPrinting, BufferPool bufferPool, Map config) { // Decorating the given stream, so that buffered contents can be // written without actually flushing the stream. this.os = new NoFlushOutputStream(out); generator = prettyPrinting - ? new JsonPrettyGeneratorImpl(os, charset, bufferPool) - : new JsonGeneratorImpl(os, charset, bufferPool); + ? new JsonPrettyGeneratorImpl(os, charset, bufferPool, config) + : new JsonGeneratorImpl(os, charset, bufferPool, config); } @Override diff --git a/impl/src/test/java/org/eclipse/parsson/tests/JsonBuilderFactoryTest.java b/impl/src/test/java/org/eclipse/parsson/tests/JsonBuilderFactoryTest.java index c7e7b292..323a0ca8 100644 --- a/impl/src/test/java/org/eclipse/parsson/tests/JsonBuilderFactoryTest.java +++ b/impl/src/test/java/org/eclipse/parsson/tests/JsonBuilderFactoryTest.java @@ -16,14 +16,20 @@ package org.eclipse.parsson.tests; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import java.util.HashMap; import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; + import jakarta.json.Json; import jakarta.json.JsonArrayBuilder; import jakarta.json.JsonBuilderFactory; import jakarta.json.JsonObject; import jakarta.json.JsonObjectBuilder; -import org.junit.Assert; -import org.junit.Test; /** * @@ -74,4 +80,37 @@ public void testObjectBuilderFromObject() { JsonObjectBuilder builder = builderFactory.createObjectBuilder(JsonBuilderTest.buildPerson()); Assert.assertEquals(JsonBuilderTest.buildPerson(), builder.build()); } + + @Test(expected = NullPointerException.class) + public void testIgnoreIfNullDefault() { + Map config = new HashMap<>(); + JsonBuilderFactory builderFactory = Json.createBuilderFactory(config); + builderFactory.createObjectBuilder() + .add("name", (String) null) + .add("age", 36) + .build(); + } + + @Test(expected = NullPointerException.class) + public void testIgnoreIfNullDisabled() { + Map config = new HashMap<>(); + config.put(JsonBuilderFactory.IGNORE_ADDING_IF_NULL, false); + JsonBuilderFactory builderFactory = Json.createBuilderFactory(config); + builderFactory.createObjectBuilder() + .add("name", (String) null) + .add("age", 36) + .build(); + } + + @Test + public void testIgnoreIfNullEnabled() { + Map config = new HashMap<>(); + config.put(JsonBuilderFactory.IGNORE_ADDING_IF_NULL, true); + JsonBuilderFactory builderFactory = Json.createBuilderFactory(config); + JsonObject jsonObject = builderFactory.createObjectBuilder() + .add("name", (String) null) + .add("age", 36) + .build(); + assertEquals(jsonObject.toString(), "{\"age\":36}"); + } } diff --git a/impl/src/test/java/org/eclipse/parsson/tests/JsonGeneratorTest.java b/impl/src/test/java/org/eclipse/parsson/tests/JsonGeneratorTest.java index bb34a786..4434bf45 100644 --- a/impl/src/test/java/org/eclipse/parsson/tests/JsonGeneratorTest.java +++ b/impl/src/test/java/org/eclipse/parsson/tests/JsonGeneratorTest.java @@ -533,6 +533,43 @@ void escapedString(String expected) throws Exception { assertEquals(expected, got); } + public void testIgnoreIfNullDefault() { + Map config = new HashMap<>(); + JsonGeneratorFactory generatorFactory = Json.createGeneratorFactory(config); + StringWriter writer = new StringWriter(); + JsonGenerator generator = generatorFactory.createGenerator(writer); + try { + generator.writeStartObject().write("val1", (String) null).writeEnd().close(); + fail("Expects a NullPointerException"); + } catch (NullPointerException e) { + // expected + } + } + + public void testIgnoreIfNullDisabled() { + Map config = new HashMap<>(); + config.put(JsonBuilderFactory.IGNORE_ADDING_IF_NULL, false); + JsonGeneratorFactory generatorFactory = Json.createGeneratorFactory(config); + StringWriter writer = new StringWriter(); + JsonGenerator generator = generatorFactory.createGenerator(writer); + try { + generator.writeStartObject().write("val1", (String) null).writeEnd().close(); + fail("Expects a NullPointerException"); + } catch (NullPointerException e) { + // expected + } + } + + public void testIgnoreIfNullEnabled() { + Map config = new HashMap<>(); + config.put(JsonBuilderFactory.IGNORE_ADDING_IF_NULL, true); + JsonGeneratorFactory generatorFactory = Json.createGeneratorFactory(config); + StringWriter writer = new StringWriter(); + JsonGenerator generator = generatorFactory.createGenerator(writer); + generator.writeStartObject().write("val1", (String) null).writeEnd().close(); + assertEquals("{}", writer.toString()); + } + public void testFlush() throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); JsonGenerator gen = Json.createGenerator(baos);