-
Notifications
You must be signed in to change notification settings - Fork 95
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
TAP5-2640: Added JSONCollectors, modified JSONObject#merge
For simpler usage with streams the class JSONCollectors provides static helper methods. During testing it became clear that the default Map#merge(...) wasn't viable for the general JSONObject logic (exception on unknow keys), so it had to be overriden and adapted.
- Loading branch information
Showing
4 changed files
with
223 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
76 changes: 76 additions & 0 deletions
76
tapestry-json/src/main/java/org/apache/tapestry5/json/JSONCollectors.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
// Copyright 2021 The Apache Software Foundation | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package org.apache.tapestry5.json; | ||
|
||
import java.util.function.Function; | ||
import java.util.stream.Collector; | ||
import java.util.stream.Collectors; | ||
|
||
/** | ||
* Implementations of {@link java.util.streams.Collector} that implement reductions | ||
* to {@code JSONArray} and to {@code JSONObject}. | ||
* | ||
* @since 5.7 | ||
*/ | ||
|
||
public final class JSONCollectors | ||
{ | ||
private JSONCollectors() | ||
{ | ||
} | ||
|
||
/** | ||
* Returns a {@code Collector} that accumulates the input elements into a | ||
* new {@code JSONArray}. | ||
* | ||
* @return a {@code Collector} which collects all the input elements into a | ||
* {@code JSONArray}, in encounter order | ||
* @since 5.7 | ||
*/ | ||
public static Collector<?, ?, JSONArray> toArray() | ||
{ | ||
return Collector.of(JSONArray::new, // | ||
JSONArray::add, JSONArray::putAll); | ||
} | ||
|
||
/** | ||
* Returns a {@code Collector} that accumulates elements into a | ||
* {@code JSONObject} whose keys and values are the result of applying the provided | ||
* mapping functions to the input elements. | ||
* | ||
* In case of duplicate keys an {@code IllegalStateException} is | ||
* thrown when the collection operation is performed. | ||
* | ||
* @param keyMapper | ||
* a mapping function to produce String keys | ||
* @param valueMapper | ||
* a mapping function to produce values | ||
* @return a {@code Collector} which collects elements into a {@code JSONObject} | ||
* whose keys and values are the result of applying mapping functions to | ||
* the input elements | ||
* @since 5.7 | ||
*/ | ||
public static Collector<?, ?, JSONObject> toMap(Function<?, String> keyMapper, | ||
Function<?, Object> valueMapper) | ||
{ | ||
return Collectors.toMap(keyMapper, | ||
valueMapper, | ||
(u, v) -> { | ||
throw new IllegalStateException(String.format("Duplicate key %s", u)); | ||
}, | ||
JSONObject::new); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
101 changes: 101 additions & 0 deletions
101
tapestry-json/src/test/groovy/json/specs/JSONCollectorsSpec.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package json.specs | ||
|
||
import org.apache.tapestry5.json.JSONCollectors | ||
import org.apache.tapestry5.json.exceptions.JSONInvalidTypeException | ||
|
||
import java.util.stream.Stream | ||
|
||
import spock.lang.Specification | ||
|
||
class JSONCollectorsSpec extends Specification { | ||
|
||
def "collect stream to array"() { | ||
|
||
given: | ||
|
||
def stringValue = "a string value" | ||
def longValue = 3L | ||
|
||
def stream = Stream.of(stringValue, longValue) | ||
|
||
when: | ||
|
||
def collected = stream.collect(JSONCollectors.toArray()); | ||
|
||
then: | ||
|
||
collected.size() == 2 | ||
collected.get(0) == stringValue | ||
collected.get(1) == longValue | ||
} | ||
|
||
def "collect stream to array invalid type"() { | ||
|
||
given: | ||
|
||
def stringValue = "a string value" | ||
def longValue = 3L | ||
def invalidValue = new java.util.Date() | ||
|
||
def stream = Stream.of(stringValue, longValue, invalidValue) | ||
|
||
when: | ||
|
||
def collected = stream.collect(JSONCollectors.toArray()); | ||
|
||
then: | ||
|
||
JSONInvalidTypeException e = thrown() | ||
} | ||
|
||
def "collect stream to map"() { | ||
|
||
given: | ||
|
||
def first = new Tuple("first key", "a string value") | ||
def second = new Tuple("second key", 3L) | ||
|
||
def stream = Stream.of(first, second) | ||
|
||
when: | ||
|
||
def collected = stream.collect(JSONCollectors.toMap({ t -> t.get(0) }, { t -> t.get(1) })); | ||
|
||
then: | ||
|
||
collected.size() == 2 | ||
collected.get(first.get(0)) == first.get(1) | ||
collected.get(second.get(0)) == second.get(1) | ||
} | ||
|
||
def "collect stream to map invalid type"() { | ||
|
||
given: | ||
|
||
def first = new Tuple("first key", "a string value") | ||
def second = new Tuple("second key", 3L) | ||
def third = new Tuple("invalid type", new java.util.Date()) | ||
|
||
def stream = Stream.of(first, second, third) | ||
|
||
when: | ||
|
||
def collected = stream.collect(JSONCollectors.toMap({ t -> t.get(0) }, { t -> t.get(1) })); | ||
|
||
then: | ||
|
||
JSONInvalidTypeException e = thrown() | ||
} | ||
|
||
def "collect stream to map duplicate key"() { | ||
|
||
when: | ||
|
||
def collected = Stream.of("first", "second", "first").collect(JSONCollectors.toMap({ v -> v }, { v -> v })) | ||
|
||
then: | ||
|
||
IllegalStateException e = thrown() | ||
} | ||
|
||
} |