Skip to content

Commit

Permalink
Add support to Jackson's JsonNode
Browse files Browse the repository at this point in the history
  • Loading branch information
oswaldobapvicjr committed Aug 14, 2022
1 parent f1087ae commit 2c60b44
Show file tree
Hide file tree
Showing 5 changed files with 326 additions and 1 deletion.
8 changes: 8 additions & 0 deletions jsonmerge-core/pom.xml
Expand Up @@ -35,6 +35,7 @@
<json-path.version>2.7.0</json-path.version>
<json-org.version>20220320</json-org.version>
<gson.version>2.9.1</gson.version>
<jackson.version>2.13.3</jackson.version>
</properties>

<dependencies>
Expand Down Expand Up @@ -73,5 +74,12 @@
<optional>true</optional>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
<optional>true</optional>
</dependency>

</dependencies>
</project>
@@ -0,0 +1,168 @@
/*
* Copyright 2022 obvj.net
*
* 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 net.obvj.jsonmerge.provider;

import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;

/**
* A specialized {@link JsonProvider} implementation for {@code Jackson}'s
* {@link JsonNode}.
*
* @author oswaldo.bapvic.jr (Oswaldo Junior)
* @since 1.0.0
*
* @see <a href="https://github.com/FasterXML/jackson">Jackson Project home</a>
* @see JsonNode
* @see ObjectNode
* @see ArrayNode
*/
public class JacksonJsonNodeJsonProvider implements JsonProvider
{
private ObjectNode toJsonObject(final Object jsonObject)
{
return (ObjectNode) jsonObject;
}

private ArrayNode toJsonArray(final Object jsonArray)
{
return (ArrayNode) jsonArray;
}

/**
* Converts an object to a {@link JsonNode}.
*
* @param object the object to be converted
* @return a {@link JsonNode} from the specified object
*/
public JsonNode toJsonNode(final Object object)
{
return object instanceof JsonNode ? (JsonNode) object
: new ObjectMapper().convertValue(object, JsonNode.class);
}

@Override
public boolean isJsonObject(final Object object)
{
return object instanceof ObjectNode;
}

@Override
public boolean isJsonArray(final Object object)
{
return object instanceof ArrayNode;
}

@Override
public boolean isEmpty(final Object jsonObject)
{
return toJsonObject(jsonObject).isEmpty();
}

@Override
public Object newJsonObject()
{
return JsonNodeFactory.instance.objectNode();
}

@Override
public Object newJsonObject(final Object sourceJsonObject)
{
return JsonNodeFactory.instance.objectNode().setAll(toJsonObject(sourceJsonObject));
}

@Override
public Object newJsonArray()
{
return JsonNodeFactory.instance.arrayNode();
}

@Override
public Object newJsonArray(final Object sourceJsonArray)
{
return JsonNodeFactory.instance.arrayNode().addAll(toJsonArray(sourceJsonArray));
}

@Override
public Set<Entry<String, Object>> entrySet(final Object jsonObject)
{
Iterator<Entry<String, JsonNode>> iterator = toJsonObject(jsonObject).fields();
Iterable<Entry<String, JsonNode>> iterable = () -> iterator;
return (Set) StreamSupport.stream(iterable.spliterator(), false).collect(Collectors.toSet());
}

@Override
public Object get(final Object jsonObject, final String key)
{
return toJsonObject(jsonObject).get(key);
}


@Override
public void put(final Object jsonObject, final String key, final Object value)
{
toJsonObject(jsonObject).set(key, toJsonNode(value));
}

@Override
public void putIfAbsent(final Object jsonObject, final String key, final Object value)
{
ObjectNode json = toJsonObject(jsonObject);
if (json.get(key) == null)
{
json.set(key, toJsonNode(value));
}
}

@Override
public void add(final Object jsonArray, final Object element)
{
toJsonArray(jsonArray).add(toJsonNode(element));
}

@Override
public void forEachElementInArray(final Object jsonArray, final Consumer<? super Object> action)
{
toJsonArray(jsonArray).forEach(action);
}

@Override
public boolean arrayContains(final Object jsonArray, final Object element)
{
return stream(jsonArray).anyMatch(element::equals);
}

@Override
public Stream<Object> stream(final Object jsonArray)
{
Spliterator<JsonNode> spliterator = toJsonArray(jsonArray).spliterator();
return (Stream) StreamSupport.stream(spliterator, false);
}

}
@@ -0,0 +1,108 @@
package net.obvj.jsonmerge;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.net.URL;
import java.util.List;

import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.ParseContext;
import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;

import net.obvj.jsonmerge.provider.JacksonJsonNodeJsonProvider;

/**
* Unit tests for the {@link JsonMerger} using the {@link JacksonJsonNodeJsonProvider}.
*
* @author oswaldo.bapvic.jr
* @since 1.0.0
*/
class JsonMergerJacksonJsonNodeJsonProviderTest extends JsonMergerTest<ObjectNode>
{

private static Configuration configuration = Configuration.builder()
.jsonProvider(new com.jayway.jsonpath.spi.json.JacksonJsonNodeJsonProvider())
.mappingProvider(new JacksonMappingProvider()).build();

private static ParseContext context = JsonPath.using(configuration);

@Override
JacksonJsonNodeJsonProvider getProvider()
{
return new JacksonJsonNodeJsonProvider();
}

@Override
ObjectNode fromString(String string)
{
try
{
return new JsonMapper().readValue(string, ObjectNode.class);
}
catch (Exception e)
{
throw new AssertionError("Unable to parse JSON string", e);
}
}

@Override
ObjectNode fromFile(String path)
{
try
{
URL resource = JsonMerger.class.getClassLoader().getResource(path);
return new JsonMapper().readValue(resource.openStream(), ObjectNode.class);
}
catch (Exception e)
{
throw new AssertionError("Unable to load JSON file", e);
}
}

@Override
Object get(ObjectNode object, String jsonPath)
{
return context.parse(object).read(jsonPath);
}

@Override
void assertElement(Object expected, Object actual)
{
assertEquals(getProvider().toJsonNode(expected), actual);
}

@Override
void assertArray(List<?> expected, ObjectNode result, String jsonPath)
{
assertArray(expected, result, jsonPath, true);
}

@Override
void assertArray(List<?> expected, ObjectNode result, String jsonPath, boolean exactSize)
{
ArrayNode array = (ArrayNode) get(result, jsonPath);
assertArray(expected, array, exactSize);
}

private void assertArray(List<?> expected, ArrayNode array, boolean exactSize)
{
if (exactSize)
{
assertEquals(expected.size(), array.size());
}

expected.forEach(expectedElement ->
{
assertTrue(
getProvider().stream(array)
.anyMatch(getProvider().toJsonNode(expectedElement)::equals),
() -> String.format("Expected element %s not found", expectedElement));
});
}

}
@@ -0,0 +1,42 @@
package net.obvj.jsonmerge.provider;

import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.Test;

import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;

/**
* Unit tests for the {@link JacksonJsonNodeJsonProvider} class.
*
* @author oswaldo.bapvic.jr
* @since 1.1.0
*/
class JacksonJsonNodeJsonProviderTest
{
private static final ArrayNode ARRAY1 = JsonNodeFactory.instance.arrayNode();

static
{
ARRAY1.add("element1");
ARRAY1.add("element2");
}

private JsonProvider provider = new JacksonJsonNodeJsonProvider();

@Test
void newJsonArray_emptyJsonArray()
{
assertEquals(JsonNodeFactory.instance.arrayNode(), provider.newJsonArray());
}

@Test
void newJsonArray_sourceJsonArray_copy()
{
Object result = provider.newJsonArray(ARRAY1);
assertEquals(ARRAY1, result);
assertNotSame(ARRAY1, result);
}

}
1 change: 0 additions & 1 deletion pom.xml
Expand Up @@ -175,7 +175,6 @@
<encoding>UTF-8</encoding>
<show>public</show>
<aggregate>false</aggregate>
<stylesheetfile>${project.basedir}/src/main/javadoc/stylesheet.css</stylesheetfile>
</configuration>
<executions>
<execution>
Expand Down

0 comments on commit 2c60b44

Please sign in to comment.