Skip to content

Commit

Permalink
add new JSONReader.Feature 'DuplicateKeyValueAsArray', for issue #379 #…
Browse files Browse the repository at this point in the history
  • Loading branch information
wenshao committed May 30, 2022
1 parent bd38c41 commit 0699011
Show file tree
Hide file tree
Showing 7 changed files with 227 additions and 42 deletions.
91 changes: 65 additions & 26 deletions core/src/main/java/com/alibaba/fastjson2/JSONPath.java
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ public JSONPath setWriterContext(JSONWriter.Context writerContext) {
return this;
}

public abstract void set(Object rootObject, Object value);
public abstract void set(Object rootObject, Object value, JSONReader.Feature... readerFeatures);

public void setCallback(Object rootObject, Function callback) {
setCallback(
Expand Down Expand Up @@ -2001,7 +2001,7 @@ public String extractScalar(JSONReader jsonReader) {
}

@Override
public void set(Object rootObject, Object value) {
public void set(Object rootObject, Object value, JSONReader.Feature... readerFeatures) {
throw new UnsupportedOperationException();
}

Expand Down Expand Up @@ -2137,9 +2137,29 @@ public boolean contains(Object root) {
}

@Override
public void set(Object rootObject, Object value) {
public void set(Object rootObject, Object value, JSONReader.Feature... readerFeatures) {
if (rootObject instanceof Map) {
((Map) rootObject).put(name, value);
Map map = (Map) rootObject;
Object origin = map.put(name, value);
if (origin != null) {
boolean duplicateKeyValueAsArray = false;
for (JSONReader.Feature feature : readerFeatures) {
if (feature == JSONReader.Feature.DuplicateKeyValueAsArray) {
duplicateKeyValueAsArray = true;
break;
}
}

if(duplicateKeyValueAsArray) {
if (origin instanceof Collection) {
((Collection) origin).add(value);
map.put(name, value);
} else {
JSONArray array = JSONArray.of(origin, value);
map.put(name, array);
}
}
}
return;
}
ObjectReaderProvider provider = getReaderContext().getProvider();
Expand Down Expand Up @@ -2627,14 +2647,14 @@ public SingleSegmentPath(Segment segment, String path) {

@Override
public boolean remove(Object root) {
Context context = new Context(this, null, segment, null);
Context context = new Context(this, null, segment, null, 0);
context.root = root;
return segment.remove(context);
}

@Override
public boolean contains(Object root) {
Context context = new Context(this, null, segment, null);
Context context = new Context(this, null, segment, null, 0);
context.root = root;
return segment.contains(context);
}
Expand All @@ -2646,50 +2666,50 @@ public boolean isRef() {

@Override
public Object eval(Object root) {
Context context = new Context(this, null, segment, null);
Context context = new Context(this, null, segment, null, 0);
context.root = root;
segment.eval(context);
return context.value;
}

@Override
public void set(Object root, Object value) {
Context context = new Context(this, null, segment, null);
public void set(Object root, Object value, JSONReader.Feature... readerFeatures) {
Context context = new Context(this, null, segment, null, 0);
context.root = root;
segment.set(context, value);
}

@Override
public void setCallback(Object root, BiFunction callback) {
Context context = new Context(this, null, segment, null);
Context context = new Context(this, null, segment, null, 0);
context.root = root;
segment.setCallback(context, callback);
}

@Override
public void setInt(Object root, int value) {
Context context = new Context(this, null, segment, null);
Context context = new Context(this, null, segment, null, 0);
context.root = root;
segment.setInt(context, value);
}

@Override
public void setLong(Object root, long value) {
Context context = new Context(this, null, segment, null);
Context context = new Context(this, null, segment, null, 0);
context.root = root;
segment.setLong(context, value);
}

@Override
public Object extract(JSONReader jsonReader) {
Context context = new Context(this, null, segment, null);
Context context = new Context(this, null, segment, null, 0);
segment.accept(jsonReader, context);
return context.value;
}

@Override
public String extractScalar(JSONReader jsonReader) {
Context context = new Context(this, null, segment, null);
Context context = new Context(this, null, segment, null, 0);
segment.accept(jsonReader, context);
return JSON.toJSONString(context.value);
}
Expand Down Expand Up @@ -2732,7 +2752,7 @@ public boolean remove(Object root) {
if (nextIndex < size) {
nextSegment = segments.get(nextIndex);
}
context = new Context(this, context, segment, nextSegment);
context = new Context(this, context, segment, nextSegment, 0);
if (i == 0) {
context.root = root;
}
Expand Down Expand Up @@ -2766,7 +2786,7 @@ public boolean contains(Object root) {
if (nextIndex < size) {
nextSegment = segments.get(nextIndex);
}
context = new Context(this, context, segment, nextSegment);
context = new Context(this, context, segment, nextSegment, 0);
if (i == 0) {
context.root = root;
}
Expand Down Expand Up @@ -2801,7 +2821,7 @@ public Object eval(Object root) {
if (nextIndex < size) {
nextSegment = segments.get(nextIndex);
}
context = new Context(this, context, segment, nextSegment);
context = new Context(this, context, segment, nextSegment, 0);
if (i == 0) {
context.root = root;
}
Expand All @@ -2812,7 +2832,12 @@ public Object eval(Object root) {
}

@Override
public void set(Object root, Object value) {
public void set(Object root, Object value, JSONReader.Feature... readerFeatures) {
long features = 0;
for (JSONReader.Feature feature : readerFeatures) {
features |= feature.mask;
}

Context context = null;
int size = segments.size();
for (int i = 0; i < size - 1; i++) {
Expand All @@ -2822,14 +2847,14 @@ public void set(Object root, Object value) {
if (nextIndex < size) {
nextSegment = segments.get(nextIndex);
}
context = new Context(this, context, segment, nextSegment);
context = new Context(this, context, segment, nextSegment, features);
if (i == 0) {
context.root = root;
}

segment.eval(context);
}
context = new Context(this, context, segments.get(0), null);
context = new Context(this, context, segments.get(0), null, features);
context.root = root;

Segment segment = segments.get(size - 1);
Expand All @@ -2847,14 +2872,14 @@ public void setCallback(Object root, BiFunction callback) {
if (nextIndex < size) {
nextSegment = segments.get(nextIndex);
}
context = new Context(this, context, segment, nextSegment);
context = new Context(this, context, segment, nextSegment, 0);
if (i == 0) {
context.root = root;
}

segment.eval(context);
}
context = new Context(this, context, segments.get(0), null);
context = new Context(this, context, segments.get(0), null, 0);
context.root = root;

Segment segment = segments.get(size - 1);
Expand Down Expand Up @@ -2892,7 +2917,7 @@ public Object extract(JSONReader jsonReader) {
nextSegment = segments.get(nextIndex);
}

context = new Context(this, context, segment, nextSegment);
context = new Context(this, context, segment, nextSegment, 0);
segment.accept(jsonReader, context);
}

Expand All @@ -2916,7 +2941,7 @@ public String extractScalar(JSONReader jsonReader) {
nextSegment = segments.get(nextIndex);
}

context = new Context(this, context, segment, nextSegment);
context = new Context(this, context, segment, nextSegment, 0);
segment.accept(jsonReader, context);
}

Expand All @@ -2929,16 +2954,18 @@ static final class Context {
final Context parent;
final Segment current;
final Segment next;
final long readerFeatures;
Object root;
Object value;

boolean eval;

Context(JSONPath path, Context parent, Segment current, Segment next) {
Context(JSONPath path, Context parent, Segment current, Segment next, long readerFeatures) {
this.path = path;
this.current = current;
this.next = next;
this.parent = parent;
this.readerFeatures = readerFeatures;
}
}

Expand Down Expand Up @@ -3456,7 +3483,19 @@ public void set(Context context, Object value) {
: context.parent.value;

if (object instanceof Map) {
((Map) object).put(name, value);
Map map = (Map) object;
Object origin = map.put(name, value);
if (origin != null) {
if((context.readerFeatures & JSONReader.Feature.DuplicateKeyValueAsArray.mask) != 0) {
if (origin instanceof Collection) {
((Collection) origin).add(value);
map.put(name, value);
} else {
JSONArray array = JSONArray.of(origin, value);
map.put(name, array);
}
}
}
return;
}

Expand Down
3 changes: 2 additions & 1 deletion core/src/main/java/com/alibaba/fastjson2/JSONReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -2386,7 +2386,8 @@ public enum Feature {
UseBigDecimalForDoubles(1 << 11),
ErrorOnEnumNotMatch(1 << 12),
TrimString(1 << 13),
ErrorOnNotSupportAutoType(1 << 14);
ErrorOnNotSupportAutoType(1 << 14),
DuplicateKeyValueAsArray(1 << 15);

public final long mask;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package com.alibaba.fastjson2.reader;

import com.alibaba.fastjson2.JSONException;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONPath;
import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.*;
import com.alibaba.fastjson2.util.*;

import java.lang.reflect.ParameterizedType;
Expand Down Expand Up @@ -438,7 +435,19 @@ public Object readObject(JSONReader jsonReader, long features) {
default:
throw new JSONException("error, offset " + jsonReader.getOffset() + ", char " + jsonReader.current());
}
object.put(name, value);
Object origin = object.put(name, value);
if (origin != null) {
long contextFeatures = features | context.getFeatures();
if ((contextFeatures & JSONReader.Feature.DuplicateKeyValueAsArray.mask) != 0) {
if (origin instanceof Collection) {
((Collection) origin).add(value);
object.put(name, value);
} else {
JSONArray array = JSONArray.of(origin, value);
object.put(name, array);
}
}
}
}

jsonReader.nextIfMatch(',');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.alibaba.fastjson2.reader;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONException;
import com.alibaba.fastjson2.JSONReader;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

Expand Down Expand Up @@ -33,10 +35,11 @@ public Object readObject(JSONReader jsonReader, long features) {
}
}

JSONReader.Context context = jsonReader.getContext();
Map<String, Object> object
= instanceType == HashMap.class
? new HashMap<>()
: (Map) createInstance(jsonReader.getContext().getFeatures() | features);
: (Map) createInstance(context.getFeatures() | features);

for (; ; ) {
if (jsonReader.nextIfMatch('}')) {
Expand All @@ -45,7 +48,19 @@ public Object readObject(JSONReader jsonReader, long features) {

String name = jsonReader.readFieldName();
String value = jsonReader.readString();
object.put(name, value);
Object origin = object.put(name, value);
if (origin != null) {
long contextFeatures = features | context.getFeatures();
if ((contextFeatures & JSONReader.Feature.DuplicateKeyValueAsArray.mask) != 0) {
if (origin instanceof Collection) {
((Collection) origin).add(value);
object.put(name, value);
} else {
JSONArray array = JSONArray.of(origin, value);
object.put(name, array);
}
}
}
}

jsonReader.nextIfMatch(',');
Expand Down
Loading

0 comments on commit 0699011

Please sign in to comment.