Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #240 - added support for "reject duplicate keys" config option #241

Merged
merged 11 commits into from
Mar 26, 2021
Merged
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand Down Expand Up @@ -33,25 +33,27 @@
class JsonBuilderFactoryImpl implements JsonBuilderFactory {
private final Map<String, ?> config;
private final BufferPool bufferPool;
private final boolean rejectDuplicateKeys;

JsonBuilderFactoryImpl(BufferPool bufferPool) {
JsonBuilderFactoryImpl(BufferPool bufferPool, boolean rejectDuplicateKeys) {
this.config = Collections.emptyMap();
this.bufferPool = bufferPool;
this.rejectDuplicateKeys = rejectDuplicateKeys;
}

@Override
public JsonObjectBuilder createObjectBuilder() {
return new JsonObjectBuilderImpl(bufferPool);
return new JsonObjectBuilderImpl(bufferPool, rejectDuplicateKeys);
}

@Override
public JsonObjectBuilder createObjectBuilder(JsonObject object) {
return new JsonObjectBuilderImpl(object, bufferPool);
return new JsonObjectBuilderImpl(object, bufferPool, rejectDuplicateKeys);
}

@Override
public JsonObjectBuilder createObjectBuilder(Map<String, Object> object) {
return new JsonObjectBuilderImpl(object, bufferPool);
return new JsonObjectBuilderImpl(object, bufferPool, rejectDuplicateKeys);
}

@Override
Expand Down
4 changes: 4 additions & 0 deletions impl/src/main/java/org/glassfish/json/JsonMessages.java
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ static String PARSER_INPUT_ENC_DETECT_FAILED() {
static String PARSER_INPUT_ENC_DETECT_IOERR() {
return localize("parser.input.enc.detect.ioerr");
}

static String DUPLICATE_KEY(String name) {
return localize("parser.duplicate.key", name);
}

// generator messages
static String GENERATOR_FLUSH_IO_ERR() {
Expand Down
33 changes: 29 additions & 4 deletions impl/src/main/java/org/glassfish/json/JsonObjectBuilderImpl.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2019 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand All @@ -18,7 +18,6 @@

import org.glassfish.json.api.BufferPool;

import jakarta.json.JsonArrayBuilder;
import jakarta.json.*;
import java.io.StringWriter;
import java.math.BigDecimal;
Expand All @@ -33,23 +32,46 @@
*/
class JsonObjectBuilderImpl implements JsonObjectBuilder {

private Map<String, JsonValue> valueMap;
protected Map<String, JsonValue> valueMap;
private final BufferPool bufferPool;
private final boolean rejectDuplicateKeys;

JsonObjectBuilderImpl(BufferPool bufferPool) {
this.bufferPool = bufferPool;
rejectDuplicateKeys = false;
}

JsonObjectBuilderImpl(BufferPool bufferPool, boolean rejectDuplicateKeys) {
this.bufferPool = bufferPool;
this.rejectDuplicateKeys = rejectDuplicateKeys;
}

JsonObjectBuilderImpl(JsonObject object, BufferPool bufferPool) {
this.bufferPool = bufferPool;
valueMap = new LinkedHashMap<>();
valueMap.putAll(object);
rejectDuplicateKeys = false;
}

JsonObjectBuilderImpl(JsonObject object, BufferPool bufferPool, boolean rejectDuplicateKeys) {
this.bufferPool = bufferPool;
valueMap = new LinkedHashMap<>();
valueMap.putAll(object);
this.rejectDuplicateKeys = rejectDuplicateKeys;
}

JsonObjectBuilderImpl(Map<String, Object> map, BufferPool bufferPool) {
this.bufferPool = bufferPool;
valueMap = new LinkedHashMap<>();
populate(map);
rejectDuplicateKeys = false;
}

JsonObjectBuilderImpl(Map<String, Object> map, BufferPool bufferPool, boolean rejectDuplicateKeys) {
this.bufferPool = bufferPool;
valueMap = new LinkedHashMap<>();
populate(map);
this.rejectDuplicateKeys = rejectDuplicateKeys;
}

@Override
Expand Down Expand Up @@ -184,7 +206,10 @@ private void putValueMap(String name, JsonValue value) {
if (valueMap == null) {
this.valueMap = new LinkedHashMap<>();
}
valueMap.put(name, value);
JsonValue previousValue = valueMap.put(name, value);
if (rejectDuplicateKeys && previousValue != null) {
throw new IllegalStateException(JsonMessages.DUPLICATE_KEY(name));
}
}

private void validateName(String name) {
Expand Down
27 changes: 22 additions & 5 deletions impl/src/main/java/org/glassfish/json/JsonParserImpl.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand All @@ -23,6 +23,7 @@
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.util.AbstractMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Spliterator;
Expand Down Expand Up @@ -55,25 +56,41 @@
public class JsonParserImpl implements JsonParser {

private final BufferPool bufferPool;
private final boolean rejectDuplicateKeys;
private Context currentContext = new NoneContext();
private Event currentEvent;

private final Stack stack = new Stack();
private final JsonTokenizer tokenizer;

public JsonParserImpl(Reader reader, BufferPool bufferPool) {
JohnTimm marked this conversation as resolved.
Show resolved Hide resolved
this(reader, bufferPool, false);
}

public JsonParserImpl(Reader reader, BufferPool bufferPool, boolean rejectDuplicateKeys) {
this.bufferPool = bufferPool;
this.rejectDuplicateKeys = rejectDuplicateKeys;
tokenizer = new JsonTokenizer(reader, bufferPool);
}

public JsonParserImpl(InputStream in, BufferPool bufferPool) {
this(in, bufferPool, false);
}

public JsonParserImpl(InputStream in, BufferPool bufferPool, boolean rejectDuplicateKeys) {
this.bufferPool = bufferPool;
this.rejectDuplicateKeys = rejectDuplicateKeys;
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);
}

public JsonParserImpl(InputStream in, Charset encoding, BufferPool bufferPool, boolean rejectDuplicateKeys) {
this.bufferPool = bufferPool;
this.rejectDuplicateKeys = rejectDuplicateKeys;
tokenizer = new JsonTokenizer(new InputStreamReader(in, encoding), bufferPool);
}

Expand Down Expand Up @@ -110,7 +127,7 @@ boolean isDefinitelyInt() {
}

boolean isDefinitelyLong() {
return tokenizer.isDefinitelyLong();
return tokenizer.isDefinitelyLong();
}

@Override
Expand Down Expand Up @@ -146,7 +163,7 @@ public JsonObject getObject() {
throw new IllegalStateException(
JsonMessages.PARSER_GETOBJECT_ERR(currentEvent));
}
return getObject(new JsonObjectBuilderImpl(bufferPool));
return getObject(new JsonObjectBuilderImpl(bufferPool, rejectDuplicateKeys));
}

@Override
Expand Down Expand Up @@ -175,7 +192,7 @@ public JsonValue getValue() {
case END_ARRAY:
case END_OBJECT:
default:
throw new IllegalStateException(JsonMessages.PARSER_GETVALUE_ERR(currentEvent));
throw new IllegalStateException(JsonMessages.PARSER_GETVALUE_ERR(currentEvent));
}
}

Expand Down
52 changes: 35 additions & 17 deletions impl/src/main/java/org/glassfish/json/JsonProviderImpl.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand All @@ -17,6 +17,7 @@
package org.glassfish.json;

import org.glassfish.json.api.BufferPool;
import org.glassfish.json.api.JsonConfig;

import jakarta.json.*;
import jakarta.json.stream.JsonGenerator;
Expand All @@ -41,7 +42,6 @@
* @author Alex Soto
*/
public class JsonProviderImpl extends JsonProvider {

private final BufferPool bufferPool = new BufferPoolImpl();

@Override
Expand Down Expand Up @@ -149,14 +149,27 @@ public JsonWriterFactory createWriterFactory(Map<String, ?> config) {

@Override
public JsonReaderFactory createReaderFactory(Map<String, ?> config) {
BufferPool pool = null;
if (config != null && config.containsKey(BufferPool.class.getName())) {
pool = (BufferPool)config.get(BufferPool.class.getName());
}
if (pool == null) {
Map<String, Object> providerConfig;
boolean rejectDuplicateKeys;
BufferPool pool;
if (config == null) {
providerConfig = Collections.emptyMap();
rejectDuplicateKeys = false;
pool = bufferPool;
} else {
providerConfig = new HashMap<>();
if (rejectDuplicateKeys = JsonProviderImpl.isRejectDuplicateKeysEnabled(config)) {
providerConfig.put(JsonConfig.REJECT_DUPLICATE_KEYS, true);
}
pool = (BufferPool) config.get(BufferPool.class.getName());
if (pool != null) {
providerConfig.put(BufferPool.class.getName(), pool);
} else {
pool = bufferPool;
}
providerConfig = Collections.unmodifiableMap(providerConfig);
}
return new JsonReaderFactoryImpl(pool);
return new JsonReaderFactoryImpl(providerConfig, pool, rejectDuplicateKeys);
}

@Override
Expand Down Expand Up @@ -255,18 +268,23 @@ public JsonNumber createValue(BigDecimal value) {
}

@Override
public JsonBuilderFactory createBuilderFactory(Map<String,?> config) {
BufferPool pool = null ;
if (config != null && config.containsKey(BufferPool.class.getName())) {
pool = (BufferPool)config.get(BufferPool.class.getName());
}
if (pool == null) {
pool = bufferPool;
}
return new JsonBuilderFactoryImpl(pool);
public JsonBuilderFactory createBuilderFactory(Map<String, ?> config) {
BufferPool pool = bufferPool;
boolean rejectDuplicateKeys = false;
if (config != null) {
if (config.containsKey(BufferPool.class.getName())) {
pool = (BufferPool) config.get(BufferPool.class.getName());
}
rejectDuplicateKeys = JsonProviderImpl.isRejectDuplicateKeysEnabled(config);
}
return new JsonBuilderFactoryImpl(pool, rejectDuplicateKeys);
}

static boolean isPrettyPrintingEnabled(Map<String, ?> config) {
return config.containsKey(JsonGenerator.PRETTY_PRINTING);
}

static boolean isRejectDuplicateKeysEnabled(Map<String, ?> config) {
return config.containsKey(JsonConfig.REJECT_DUPLICATE_KEYS);
}
}
14 changes: 8 additions & 6 deletions impl/src/main/java/org/glassfish/json/JsonReaderFactoryImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,33 +23,35 @@
import java.io.InputStream;
import java.io.Reader;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.Map;

/**
* @author Jitendra Kotamraju
*/
class JsonReaderFactoryImpl implements JsonReaderFactory {
private final Map<String, ?> config = Collections.emptyMap();
private final Map<String, ?> config;
private final BufferPool bufferPool;
private final boolean rejectDuplicateKeys;

JsonReaderFactoryImpl(BufferPool bufferPool) {
JsonReaderFactoryImpl(Map<String, ?> config, BufferPool bufferPool, boolean rejectDuplicateKeys) {
this.config = config;
this.bufferPool = bufferPool;
this.rejectDuplicateKeys = rejectDuplicateKeys;
}

@Override
public JsonReader createReader(Reader reader) {
return new JsonReaderImpl(reader, bufferPool);
return new JsonReaderImpl(reader, bufferPool, rejectDuplicateKeys);
}

@Override
public JsonReader createReader(InputStream in) {
return new JsonReaderImpl(in, bufferPool);
return new JsonReaderImpl(in, bufferPool, rejectDuplicateKeys);
}

@Override
public JsonReader createReader(InputStream in, Charset charset) {
return new JsonReaderImpl(in, charset, bufferPool);
return new JsonReaderImpl(in, charset, bufferPool, rejectDuplicateKeys);
}

@Override
Expand Down
20 changes: 16 additions & 4 deletions impl/src/main/java/org/glassfish/json/JsonReaderImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,19 +39,31 @@ class JsonReaderImpl implements JsonReader {
private final JsonParserImpl parser;
private boolean readDone;
private final BufferPool bufferPool;

JsonReaderImpl(Reader reader, BufferPool bufferPool) {
parser = new JsonParserImpl(reader, bufferPool);
this(reader, bufferPool, false);
}

JsonReaderImpl(Reader reader, BufferPool bufferPool, boolean rejectDuplicateKeys) {
parser = new JsonParserImpl(reader, bufferPool, rejectDuplicateKeys);
this.bufferPool = bufferPool;
}

JsonReaderImpl(InputStream in, BufferPool bufferPool) {
parser = new JsonParserImpl(in, bufferPool);
this(in, bufferPool, false);
}

JsonReaderImpl(InputStream in, BufferPool bufferPool, boolean rejectDuplicateKeys) {
parser = new JsonParserImpl(in, bufferPool, rejectDuplicateKeys);
this.bufferPool = bufferPool;
}

JsonReaderImpl(InputStream in, Charset charset, BufferPool bufferPool) {
parser = new JsonParserImpl(in, charset, bufferPool);
this(in, charset, bufferPool, false);
}

JsonReaderImpl(InputStream in, Charset charset, BufferPool bufferPool, boolean rejectDuplicateKeys) {
parser = new JsonParserImpl(in, charset, bufferPool, rejectDuplicateKeys);
this.bufferPool = bufferPool;
}

Expand Down
Loading