Skip to content

Commit f0a26c5

Browse files
authored
Issue #240 - added support for "reject duplicate keys" config option (#241)
added option: REJECT_DUPLICATE_KEYS Signed-off-by: John T.E. Timm <[email protected]>
1 parent 62c57bc commit f0a26c5

File tree

11 files changed

+227
-42
lines changed

11 files changed

+227
-42
lines changed

impl/src/main/java/org/glassfish/json/JsonBuilderFactoryImpl.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2013, 2021 Oracle and/or its affiliates. All rights reserved.
33
*
44
* This program and the accompanying materials are made available under the
55
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -33,25 +33,27 @@
3333
class JsonBuilderFactoryImpl implements JsonBuilderFactory {
3434
private final Map<String, ?> config;
3535
private final BufferPool bufferPool;
36+
private final boolean rejectDuplicateKeys;
3637

37-
JsonBuilderFactoryImpl(BufferPool bufferPool) {
38+
JsonBuilderFactoryImpl(BufferPool bufferPool, boolean rejectDuplicateKeys) {
3839
this.config = Collections.emptyMap();
3940
this.bufferPool = bufferPool;
41+
this.rejectDuplicateKeys = rejectDuplicateKeys;
4042
}
4143

4244
@Override
4345
public JsonObjectBuilder createObjectBuilder() {
44-
return new JsonObjectBuilderImpl(bufferPool);
46+
return new JsonObjectBuilderImpl(bufferPool, rejectDuplicateKeys);
4547
}
4648

4749
@Override
4850
public JsonObjectBuilder createObjectBuilder(JsonObject object) {
49-
return new JsonObjectBuilderImpl(object, bufferPool);
51+
return new JsonObjectBuilderImpl(object, bufferPool, rejectDuplicateKeys);
5052
}
5153

5254
@Override
5355
public JsonObjectBuilder createObjectBuilder(Map<String, Object> object) {
54-
return new JsonObjectBuilderImpl(object, bufferPool);
56+
return new JsonObjectBuilderImpl(object, bufferPool, rejectDuplicateKeys);
5557
}
5658

5759
@Override

impl/src/main/java/org/glassfish/json/JsonMessages.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ static String PARSER_INPUT_ENC_DETECT_FAILED() {
116116
static String PARSER_INPUT_ENC_DETECT_IOERR() {
117117
return localize("parser.input.enc.detect.ioerr");
118118
}
119+
120+
static String DUPLICATE_KEY(String name) {
121+
return localize("parser.duplicate.key", name);
122+
}
119123

120124
// generator messages
121125
static String GENERATOR_FLUSH_IO_ERR() {

impl/src/main/java/org/glassfish/json/JsonObjectBuilderImpl.java

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2012, 2019 Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
33
*
44
* This program and the accompanying materials are made available under the
55
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -18,7 +18,6 @@
1818

1919
import org.glassfish.json.api.BufferPool;
2020

21-
import jakarta.json.JsonArrayBuilder;
2221
import jakarta.json.*;
2322
import java.io.StringWriter;
2423
import java.math.BigDecimal;
@@ -33,23 +32,46 @@
3332
*/
3433
class JsonObjectBuilderImpl implements JsonObjectBuilder {
3534

36-
private Map<String, JsonValue> valueMap;
35+
protected Map<String, JsonValue> valueMap;
3736
private final BufferPool bufferPool;
37+
private final boolean rejectDuplicateKeys;
3838

3939
JsonObjectBuilderImpl(BufferPool bufferPool) {
4040
this.bufferPool = bufferPool;
41+
rejectDuplicateKeys = false;
42+
}
43+
44+
JsonObjectBuilderImpl(BufferPool bufferPool, boolean rejectDuplicateKeys) {
45+
this.bufferPool = bufferPool;
46+
this.rejectDuplicateKeys = rejectDuplicateKeys;
4147
}
4248

4349
JsonObjectBuilderImpl(JsonObject object, BufferPool bufferPool) {
4450
this.bufferPool = bufferPool;
4551
valueMap = new LinkedHashMap<>();
4652
valueMap.putAll(object);
53+
rejectDuplicateKeys = false;
54+
}
55+
56+
JsonObjectBuilderImpl(JsonObject object, BufferPool bufferPool, boolean rejectDuplicateKeys) {
57+
this.bufferPool = bufferPool;
58+
valueMap = new LinkedHashMap<>();
59+
valueMap.putAll(object);
60+
this.rejectDuplicateKeys = rejectDuplicateKeys;
4761
}
4862

4963
JsonObjectBuilderImpl(Map<String, Object> map, BufferPool bufferPool) {
5064
this.bufferPool = bufferPool;
5165
valueMap = new LinkedHashMap<>();
5266
populate(map);
67+
rejectDuplicateKeys = false;
68+
}
69+
70+
JsonObjectBuilderImpl(Map<String, Object> map, BufferPool bufferPool, boolean rejectDuplicateKeys) {
71+
this.bufferPool = bufferPool;
72+
valueMap = new LinkedHashMap<>();
73+
populate(map);
74+
this.rejectDuplicateKeys = rejectDuplicateKeys;
5375
}
5476

5577
@Override
@@ -184,7 +206,10 @@ private void putValueMap(String name, JsonValue value) {
184206
if (valueMap == null) {
185207
this.valueMap = new LinkedHashMap<>();
186208
}
187-
valueMap.put(name, value);
209+
JsonValue previousValue = valueMap.put(name, value);
210+
if (rejectDuplicateKeys && previousValue != null) {
211+
throw new IllegalStateException(JsonMessages.DUPLICATE_KEY(name));
212+
}
188213
}
189214

190215
private void validateName(String name) {

impl/src/main/java/org/glassfish/json/JsonParserImpl.java

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
33
*
44
* This program and the accompanying materials are made available under the
55
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -23,6 +23,7 @@
2323
import java.math.BigDecimal;
2424
import java.nio.charset.Charset;
2525
import java.util.AbstractMap;
26+
import java.util.LinkedHashMap;
2627
import java.util.Map;
2728
import java.util.NoSuchElementException;
2829
import java.util.Spliterator;
@@ -55,25 +56,41 @@
5556
public class JsonParserImpl implements JsonParser {
5657

5758
private final BufferPool bufferPool;
59+
private final boolean rejectDuplicateKeys;
5860
private Context currentContext = new NoneContext();
5961
private Event currentEvent;
6062

6163
private final Stack stack = new Stack();
6264
private final JsonTokenizer tokenizer;
63-
65+
6466
public JsonParserImpl(Reader reader, BufferPool bufferPool) {
67+
this(reader, bufferPool, false);
68+
}
69+
70+
public JsonParserImpl(Reader reader, BufferPool bufferPool, boolean rejectDuplicateKeys) {
6571
this.bufferPool = bufferPool;
72+
this.rejectDuplicateKeys = rejectDuplicateKeys;
6673
tokenizer = new JsonTokenizer(reader, bufferPool);
6774
}
6875

6976
public JsonParserImpl(InputStream in, BufferPool bufferPool) {
77+
this(in, bufferPool, false);
78+
}
79+
80+
public JsonParserImpl(InputStream in, BufferPool bufferPool, boolean rejectDuplicateKeys) {
7081
this.bufferPool = bufferPool;
82+
this.rejectDuplicateKeys = rejectDuplicateKeys;
7183
UnicodeDetectingInputStream uin = new UnicodeDetectingInputStream(in);
7284
tokenizer = new JsonTokenizer(new InputStreamReader(uin, uin.getCharset()), bufferPool);
7385
}
7486

7587
public JsonParserImpl(InputStream in, Charset encoding, BufferPool bufferPool) {
88+
this(in, encoding, bufferPool, false);
89+
}
90+
91+
public JsonParserImpl(InputStream in, Charset encoding, BufferPool bufferPool, boolean rejectDuplicateKeys) {
7692
this.bufferPool = bufferPool;
93+
this.rejectDuplicateKeys = rejectDuplicateKeys;
7794
tokenizer = new JsonTokenizer(new InputStreamReader(in, encoding), bufferPool);
7895
}
7996

@@ -110,7 +127,7 @@ boolean isDefinitelyInt() {
110127
}
111128

112129
boolean isDefinitelyLong() {
113-
return tokenizer.isDefinitelyLong();
130+
return tokenizer.isDefinitelyLong();
114131
}
115132

116133
@Override
@@ -146,7 +163,7 @@ public JsonObject getObject() {
146163
throw new IllegalStateException(
147164
JsonMessages.PARSER_GETOBJECT_ERR(currentEvent));
148165
}
149-
return getObject(new JsonObjectBuilderImpl(bufferPool));
166+
return getObject(new JsonObjectBuilderImpl(bufferPool, rejectDuplicateKeys));
150167
}
151168

152169
@Override
@@ -175,7 +192,7 @@ public JsonValue getValue() {
175192
case END_ARRAY:
176193
case END_OBJECT:
177194
default:
178-
throw new IllegalStateException(JsonMessages.PARSER_GETVALUE_ERR(currentEvent));
195+
throw new IllegalStateException(JsonMessages.PARSER_GETVALUE_ERR(currentEvent));
179196
}
180197
}
181198

impl/src/main/java/org/glassfish/json/JsonProviderImpl.java

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
33
*
44
* This program and the accompanying materials are made available under the
55
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -17,6 +17,7 @@
1717
package org.glassfish.json;
1818

1919
import org.glassfish.json.api.BufferPool;
20+
import org.glassfish.json.api.JsonConfig;
2021

2122
import jakarta.json.*;
2223
import jakarta.json.stream.JsonGenerator;
@@ -41,7 +42,6 @@
4142
* @author Alex Soto
4243
*/
4344
public class JsonProviderImpl extends JsonProvider {
44-
4545
private final BufferPool bufferPool = new BufferPoolImpl();
4646

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

150150
@Override
151151
public JsonReaderFactory createReaderFactory(Map<String, ?> config) {
152-
BufferPool pool = null;
153-
if (config != null && config.containsKey(BufferPool.class.getName())) {
154-
pool = (BufferPool)config.get(BufferPool.class.getName());
155-
}
156-
if (pool == null) {
152+
Map<String, Object> providerConfig;
153+
boolean rejectDuplicateKeys;
154+
BufferPool pool;
155+
if (config == null) {
156+
providerConfig = Collections.emptyMap();
157+
rejectDuplicateKeys = false;
157158
pool = bufferPool;
159+
} else {
160+
providerConfig = new HashMap<>();
161+
if (rejectDuplicateKeys = JsonProviderImpl.isRejectDuplicateKeysEnabled(config)) {
162+
providerConfig.put(JsonConfig.REJECT_DUPLICATE_KEYS, true);
163+
}
164+
pool = (BufferPool) config.get(BufferPool.class.getName());
165+
if (pool != null) {
166+
providerConfig.put(BufferPool.class.getName(), pool);
167+
} else {
168+
pool = bufferPool;
169+
}
170+
providerConfig = Collections.unmodifiableMap(providerConfig);
158171
}
159-
return new JsonReaderFactoryImpl(pool);
172+
return new JsonReaderFactoryImpl(providerConfig, pool, rejectDuplicateKeys);
160173
}
161174

162175
@Override
@@ -255,18 +268,23 @@ public JsonNumber createValue(BigDecimal value) {
255268
}
256269

257270
@Override
258-
public JsonBuilderFactory createBuilderFactory(Map<String,?> config) {
259-
BufferPool pool = null ;
260-
if (config != null && config.containsKey(BufferPool.class.getName())) {
261-
pool = (BufferPool)config.get(BufferPool.class.getName());
262-
}
263-
if (pool == null) {
264-
pool = bufferPool;
265-
}
266-
return new JsonBuilderFactoryImpl(pool);
271+
public JsonBuilderFactory createBuilderFactory(Map<String, ?> config) {
272+
BufferPool pool = bufferPool;
273+
boolean rejectDuplicateKeys = false;
274+
if (config != null) {
275+
if (config.containsKey(BufferPool.class.getName())) {
276+
pool = (BufferPool) config.get(BufferPool.class.getName());
277+
}
278+
rejectDuplicateKeys = JsonProviderImpl.isRejectDuplicateKeysEnabled(config);
279+
}
280+
return new JsonBuilderFactoryImpl(pool, rejectDuplicateKeys);
267281
}
268282

269283
static boolean isPrettyPrintingEnabled(Map<String, ?> config) {
270284
return config.containsKey(JsonGenerator.PRETTY_PRINTING);
271285
}
286+
287+
static boolean isRejectDuplicateKeysEnabled(Map<String, ?> config) {
288+
return config.containsKey(JsonConfig.REJECT_DUPLICATE_KEYS);
289+
}
272290
}

impl/src/main/java/org/glassfish/json/JsonReaderFactoryImpl.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,33 +23,35 @@
2323
import java.io.InputStream;
2424
import java.io.Reader;
2525
import java.nio.charset.Charset;
26-
import java.util.Collections;
2726
import java.util.Map;
2827

2928
/**
3029
* @author Jitendra Kotamraju
3130
*/
3231
class JsonReaderFactoryImpl implements JsonReaderFactory {
33-
private final Map<String, ?> config = Collections.emptyMap();
32+
private final Map<String, ?> config;
3433
private final BufferPool bufferPool;
34+
private final boolean rejectDuplicateKeys;
3535

36-
JsonReaderFactoryImpl(BufferPool bufferPool) {
36+
JsonReaderFactoryImpl(Map<String, ?> config, BufferPool bufferPool, boolean rejectDuplicateKeys) {
37+
this.config = config;
3738
this.bufferPool = bufferPool;
39+
this.rejectDuplicateKeys = rejectDuplicateKeys;
3840
}
3941

4042
@Override
4143
public JsonReader createReader(Reader reader) {
42-
return new JsonReaderImpl(reader, bufferPool);
44+
return new JsonReaderImpl(reader, bufferPool, rejectDuplicateKeys);
4345
}
4446

4547
@Override
4648
public JsonReader createReader(InputStream in) {
47-
return new JsonReaderImpl(in, bufferPool);
49+
return new JsonReaderImpl(in, bufferPool, rejectDuplicateKeys);
4850
}
4951

5052
@Override
5153
public JsonReader createReader(InputStream in, Charset charset) {
52-
return new JsonReaderImpl(in, charset, bufferPool);
54+
return new JsonReaderImpl(in, charset, bufferPool, rejectDuplicateKeys);
5355
}
5456

5557
@Override

impl/src/main/java/org/glassfish/json/JsonReaderImpl.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,31 @@ class JsonReaderImpl implements JsonReader {
3939
private final JsonParserImpl parser;
4040
private boolean readDone;
4141
private final BufferPool bufferPool;
42-
42+
4343
JsonReaderImpl(Reader reader, BufferPool bufferPool) {
44-
parser = new JsonParserImpl(reader, bufferPool);
44+
this(reader, bufferPool, false);
45+
}
46+
47+
JsonReaderImpl(Reader reader, BufferPool bufferPool, boolean rejectDuplicateKeys) {
48+
parser = new JsonParserImpl(reader, bufferPool, rejectDuplicateKeys);
4549
this.bufferPool = bufferPool;
4650
}
4751

4852
JsonReaderImpl(InputStream in, BufferPool bufferPool) {
49-
parser = new JsonParserImpl(in, bufferPool);
53+
this(in, bufferPool, false);
54+
}
55+
56+
JsonReaderImpl(InputStream in, BufferPool bufferPool, boolean rejectDuplicateKeys) {
57+
parser = new JsonParserImpl(in, bufferPool, rejectDuplicateKeys);
5058
this.bufferPool = bufferPool;
5159
}
5260

5361
JsonReaderImpl(InputStream in, Charset charset, BufferPool bufferPool) {
54-
parser = new JsonParserImpl(in, charset, bufferPool);
62+
this(in, charset, bufferPool, false);
63+
}
64+
65+
JsonReaderImpl(InputStream in, Charset charset, BufferPool bufferPool, boolean rejectDuplicateKeys) {
66+
parser = new JsonParserImpl(in, charset, bufferPool, rejectDuplicateKeys);
5567
this.bufferPool = bufferPool;
5668
}
5769

0 commit comments

Comments
 (0)