INT-4241: Wrap ArrayNodes with ArrayNodeAsList
JIRA: https://jira.spring.io/browse/INT-4241 To allow `ArrayNode` to be treated as `List` in SpEL expressions, wrap them to the internal `ArrayNodeAsList` implementation Fix Checkstyle errors * Add `iterator()` support to the `ArrayNodeAsList`
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2016 the original author or authors.
|
||||
* Copyright 2013-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,6 +17,8 @@
|
||||
package org.springframework.integration.json;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.AbstractList;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.springframework.expression.AccessException;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
@@ -36,6 +38,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
*
|
||||
* @author Eric Bottard
|
||||
* @author Artem Bilan
|
||||
* @author Paul Martin
|
||||
* @since 3.0
|
||||
*/
|
||||
public class JsonPropertyAccessor implements PropertyAccessor {
|
||||
@@ -44,7 +47,7 @@ public class JsonPropertyAccessor implements PropertyAccessor {
|
||||
* The kind of types this can work with.
|
||||
*/
|
||||
private static final Class<?>[] SUPPORTED_CLASSES = new Class<?>[] { String.class, ToStringFriendlyJsonNode.class,
|
||||
ObjectNode.class, ArrayNode.class };
|
||||
ArrayNodeAsList.class, ObjectNode.class, ArrayNode.class };
|
||||
|
||||
// Note: ObjectMapper is thread-safe
|
||||
private ObjectMapper objectMapper = new ObjectMapper();
|
||||
@@ -58,7 +61,12 @@ public class JsonPropertyAccessor implements PropertyAccessor {
|
||||
public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
ContainerNode<?> container = asJson(target);
|
||||
Integer index = maybeIndex(name);
|
||||
return ((index != null && container.has(index)) || container.has(name));
|
||||
if (container instanceof ArrayNode) {
|
||||
return index != null;
|
||||
}
|
||||
else {
|
||||
return ((index != null && container.has(index)) || container.has(name));
|
||||
}
|
||||
}
|
||||
|
||||
private ContainerNode<?> assertContainerNode(JsonNode json) throws AccessException {
|
||||
@@ -79,6 +87,10 @@ public class JsonPropertyAccessor implements PropertyAccessor {
|
||||
ToStringFriendlyJsonNode wrapper = (ToStringFriendlyJsonNode) target;
|
||||
return assertContainerNode(wrapper.node);
|
||||
}
|
||||
else if (target instanceof ArrayNodeAsList) {
|
||||
ArrayNodeAsList wrapper = (ArrayNodeAsList) target;
|
||||
return assertContainerNode(wrapper.node);
|
||||
}
|
||||
else if (target instanceof String) {
|
||||
try {
|
||||
JsonNode json = this.objectMapper.readTree((String) target);
|
||||
@@ -113,16 +125,10 @@ public class JsonPropertyAccessor implements PropertyAccessor {
|
||||
ContainerNode<?> container = asJson(target);
|
||||
Integer index = maybeIndex(name);
|
||||
if (index != null && container.has(index)) {
|
||||
return new TypedValue(wrap(container.get(index)));
|
||||
return typedValue(container.get(index));
|
||||
}
|
||||
else {
|
||||
JsonNode json = container.get(name);
|
||||
if (json != null) {
|
||||
return new TypedValue(wrap(json));
|
||||
}
|
||||
else {
|
||||
return TypedValue.NULL;
|
||||
}
|
||||
return typedValue(container.get(name));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,15 +147,43 @@ public class JsonPropertyAccessor implements PropertyAccessor {
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
private ToStringFriendlyJsonNode wrap(JsonNode json) {
|
||||
return new ToStringFriendlyJsonNode(json);
|
||||
private static TypedValue typedValue(JsonNode json) {
|
||||
if (json == null) {
|
||||
return TypedValue.NULL;
|
||||
}
|
||||
else {
|
||||
return new TypedValue(wrap(json));
|
||||
}
|
||||
}
|
||||
|
||||
public static class ToStringFriendlyJsonNode {
|
||||
public static WrappedJsonNode wrap(JsonNode json) {
|
||||
if (json == null) {
|
||||
return null;
|
||||
}
|
||||
else if (json instanceof ArrayNode) {
|
||||
return new ArrayNodeAsList((ArrayNode) json);
|
||||
}
|
||||
else {
|
||||
return new ToStringFriendlyJsonNode(json);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The base interface for wrapped {@link JsonNode}.
|
||||
* @since 5.0
|
||||
*/
|
||||
public interface WrappedJsonNode {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link WrappedJsonNode} implementation to represent {@link JsonNode} as string.
|
||||
*/
|
||||
public static class ToStringFriendlyJsonNode implements WrappedJsonNode {
|
||||
|
||||
private final JsonNode node;
|
||||
|
||||
public ToStringFriendlyJsonNode(JsonNode node) {
|
||||
ToStringFriendlyJsonNode(JsonNode node) {
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
@@ -186,4 +220,48 @@ public class JsonPropertyAccessor implements PropertyAccessor {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link AbstractList} implementation around {@link ArrayNode} with {@link WrappedJsonNode} aspect.
|
||||
* @since 5.0
|
||||
*/
|
||||
public static class ArrayNodeAsList extends AbstractList<WrappedJsonNode> implements WrappedJsonNode {
|
||||
|
||||
private final ArrayNode node;
|
||||
|
||||
ArrayNodeAsList(ArrayNode node) {
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WrappedJsonNode get(int index) {
|
||||
return wrap(this.node.get(index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return this.node.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<WrappedJsonNode> iterator() {
|
||||
|
||||
return new Iterator<WrappedJsonNode>() {
|
||||
|
||||
private final Iterator<JsonNode> delegate = ArrayNodeAsList.this.node.iterator();
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return this.delegate.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public WrappedJsonNode next() {
|
||||
return wrap(this.delegate.next());
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user