
io.micronaut.serde.support.util.JsonNodeDecoder Maven / Gradle / Ivy
/*
* Copyright 2017-2021 original authors
*
* 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
*
* https://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 io.micronaut.serde.support.util;
import io.micronaut.core.annotation.Internal;
import io.micronaut.core.annotation.NonNull;
import io.micronaut.core.type.Argument;
import io.micronaut.core.util.CollectionUtils;
import io.micronaut.json.tree.JsonNode;
import io.micronaut.serde.Decoder;
import io.micronaut.serde.LimitingStream;
import io.micronaut.serde.exceptions.InvalidFormatException;
import io.micronaut.serde.exceptions.SerdeException;
import io.micronaut.serde.util.BinaryCodecUtil;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Implementation of the {@link io.micronaut.serde.Decoder} interface that
* uses the {@link io.micronaut.json.tree.JsonNode} abstraction.
*/
@Internal
public abstract sealed class JsonNodeDecoder extends LimitingStream implements Decoder permits JsonArrayNodeDecoder, JsonNodeDecoder.Buffered, JsonObjectNodeDecoder {
JsonNodeDecoder(LimitingStream.RemainingLimits remainingLimits) {
super(remainingLimits);
}
public static JsonNodeDecoder create(JsonNode node, LimitingStream.RemainingLimits remainingLimits) {
return new Buffered(node, remainingLimits);
}
protected abstract JsonNode peekValue() throws IOException;
@Override
public Decoder decodeArray(Argument> type) throws IOException {
JsonNode peeked = peekValue();
if (peeked.isArray()) {
skipValue();
return new JsonArrayNodeDecoder(peeked, childLimits());
} else {
throw createDeserializationException("Not an array", toArbitrary(peeked));
}
}
@Override
public Decoder decodeObject(Argument> type) throws IOException {
JsonNode peeked = peekValue();
if (peeked.isObject()) {
skipValue();
return new JsonObjectNodeDecoder(peeked, childLimits());
} else {
throw createDeserializationException("Not an array", toArbitrary(peeked));
}
}
@Override
public String decodeString() throws IOException {
JsonNode peeked = peekValue();
if (peeked.isString()) {
skipValue();
return peeked.getStringValue();
} else if (peeked.isArray()) {
try (Decoder decoder = decodeArray(Argument.STRING)) {
String unwrapped = decoder.decodeString();
if (decoder.hasNextArrayValue()) {
throw createDeserializationException("Expected one string, but got array of multiple values", null);
} else {
return unwrapped;
}
}
} else {
throw createDeserializationException("Not a string", toArbitrary(peeked));
}
}
@Override
public boolean decodeBoolean() throws IOException {
JsonNode peeked = peekValue();
if (peeked.isBoolean()) {
skipValue();
return peeked.getBooleanValue();
} else if (peeked.isArray()) {
try (Decoder decoder = decodeArray(Argument.BOOLEAN)) {
boolean unwrapped = decoder.decodeBoolean();
if (decoder.hasNextArrayValue()) {
throw createDeserializationException("Expected one boolean, but got array of multiple values", null);
} else {
return unwrapped;
}
}
} else {
throw createDeserializationException("Not a boolean", toArbitrary(peeked));
}
}
@Override
public byte decodeByte() throws IOException {
JsonNode peeked = peekValue();
if (peeked.isNumber()) {
skipValue();
return (byte) peeked.getIntValue();
} else if (peeked.isArray()) {
try (Decoder decoder = decodeArray(Argument.BYTE)) {
byte unwrapped = decoder.decodeByte();
if (decoder.hasNextArrayValue()) {
throw createDeserializationException("Expected one byte, but got array of multiple values", null);
} else {
return unwrapped;
}
}
} else {
throw createDeserializationException("Not a number", toArbitrary(peeked));
}
}
@Override
public short decodeShort() throws IOException {
JsonNode peeked = peekValue();
if (peeked.isNumber()) {
skipValue();
return (short) peeked.getIntValue();
} else if (peeked.isArray()) {
try (Decoder decoder = decodeArray(Argument.SHORT)) {
short unwrapped = decoder.decodeShort();
if (decoder.hasNextArrayValue()) {
throw createDeserializationException("Expected one short, but got array of multiple values", null);
} else {
return unwrapped;
}
}
} else {
throw createDeserializationException("Not a number", toArbitrary(peeked));
}
}
@Override
public char decodeChar() throws IOException {
JsonNode peeked = peekValue();
if (peeked.isNumber()) {
skipValue();
return (char) peeked.getIntValue();
} else if (peeked.isArray()) {
try (Decoder decoder = decodeArray(Argument.CHAR)) {
char unwrapped = decoder.decodeChar();
if (decoder.hasNextArrayValue()) {
throw createDeserializationException("Expected one char, but got array of multiple values", null);
} else {
return unwrapped;
}
}
} else {
throw createDeserializationException("Not a number", toArbitrary(peeked));
}
}
@Override
public int decodeInt() throws IOException {
JsonNode peeked = peekValue();
if (peeked.isNumber()) {
skipValue();
return peeked.getIntValue();
} else if (peeked.isArray()) {
try (Decoder decoder = decodeArray(Argument.INT)) {
int unwrapped = decoder.decodeInt();
if (decoder.hasNextArrayValue()) {
throw createDeserializationException("Expected one int, but got array of multiple values", null);
} else {
return unwrapped;
}
}
} else {
throw createDeserializationException("Not a number", toArbitrary(peeked));
}
}
@Override
public long decodeLong() throws IOException {
JsonNode peeked = peekValue();
if (peeked.isNumber()) {
skipValue();
return peeked.getLongValue();
} else if (peeked.isArray()) {
try (Decoder decoder = decodeArray(Argument.LONG)) {
long unwrapped = decoder.decodeLong();
if (decoder.hasNextArrayValue()) {
throw createDeserializationException("Expected one long, but got array of multiple values", null);
} else {
return unwrapped;
}
}
} else {
throw createDeserializationException("Not a number", toArbitrary(peeked));
}
}
@Override
public float decodeFloat() throws IOException {
JsonNode peeked = peekValue();
if (peeked.isNumber()) {
skipValue();
return peeked.getFloatValue();
} else if (peeked.isArray()) {
try (Decoder decoder = decodeArray(Argument.FLOAT)) {
float unwrapped = decoder.decodeFloat();
if (decoder.hasNextArrayValue()) {
throw createDeserializationException("Expected one float, but got array of multiple values", null);
} else {
return unwrapped;
}
}
} else {
throw createDeserializationException("Not a number", toArbitrary(peeked));
}
}
@Override
public double decodeDouble() throws IOException {
JsonNode peeked = peekValue();
if (peeked.isNumber()) {
skipValue();
return peeked.getDoubleValue();
} else if (peeked.isArray()) {
try (Decoder decoder = decodeArray(Argument.DOUBLE)) {
double unwrapped = decoder.decodeDouble();
if (decoder.hasNextArrayValue()) {
throw createDeserializationException("Expected one double, but got array of multiple values", null);
} else {
return unwrapped;
}
}
} else {
throw createDeserializationException("Not a number", toArbitrary(peeked));
}
}
@Override
public BigInteger decodeBigInteger() throws IOException {
JsonNode peeked = peekValue();
if (peeked.isNumber()) {
skipValue();
return peeked.getBigIntegerValue();
} else if (peeked.isArray()) {
try (Decoder decoder = decodeArray()) {
BigInteger unwrapped = decoder.decodeBigInteger();
if (decoder.hasNextArrayValue()) {
throw createDeserializationException("Expected one BigInteger, but got array of multiple values", null);
} else {
return unwrapped;
}
}
} else {
throw createDeserializationException("Not a number", toArbitrary(peeked));
}
}
@Override
public BigDecimal decodeBigDecimal() throws IOException {
JsonNode peeked = peekValue();
if (peeked.isNumber()) {
skipValue();
return peeked.getBigDecimalValue();
} else if (peeked.isArray()) {
try (Decoder decoder = decodeArray()) {
BigDecimal unwrapped = decoder.decodeBigDecimal();
if (decoder.hasNextArrayValue()) {
throw createDeserializationException("Expected one BigDecimal, but got array of multiple values", null);
} else {
return unwrapped;
}
}
} else {
throw createDeserializationException("Not a number", toArbitrary(peeked));
}
}
@Override
public byte @NonNull [] decodeBinary() throws IOException {
JsonNode peeked = peekValue();
if (peeked.isString()) {
return BinaryCodecUtil.decodeFromBase64String(this);
} else {
return BinaryCodecUtil.decodeFromArray(this);
}
}
@Override
public boolean decodeNull() throws IOException {
JsonNode peeked = peekValue();
if (peeked.isNull()) {
skipValue();
return true;
} else {
return false;
}
}
@Override
public Object decodeArbitrary() throws IOException {
return toArbitrary(decodeNode());
}
@NonNull
@Override
public JsonNode decodeNode() throws IOException {
JsonNode node = peekValue();
skipValue();
return node;
}
private static Object toArbitrary(JsonNode node) {
if (node.isNull()) {
return null;
} else if (node.isNumber()) {
return node.getNumberValue();
} else if (node.isBoolean()) {
return node.getBooleanValue();
} else if (node.isString()) {
return node.getStringValue();
} else if (node.isArray()) {
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy