package io.oasp.module.rest.service.impl.json; import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Calendar; import java.util.Date; import net.sf.mmm.util.date.base.Iso8601UtilImpl; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; /** * Helper class to simplify implementation of {@link JsonDeserializer}. * * @param <T> the class to be deserialized */ public abstract class AbstractJsonDeserializer<T> extends JsonDeserializer<T> { /** * @param <V> the type to convert the requested value to. * @param node parent node to deserialize * @param fieldName the name of the JSON property to get the value from. * @param type the {@link Class} reflecting the type to convert the requested value to. * @return requested value converted to the given {@code type}. May not be {@code null}. * @throws RuntimeException if the requested value is not present or if the conversion failed. */ protected <V> V getRequiredValue(JsonNode node, String fieldName, Class<V> type) throws RuntimeException { return getValue(node, fieldName, type, true); } /** * @param <V> the type to convert the requested value to. * @param node parent node to deserialize * @param fieldName the name of the JSON property to get the value from. * @param type the {@link Class} reflecting the type to convert the requested value to. * @param fallback is the default returned if the requested value is undefined. * @return requested value converted to the given {@code type} or {@code fallback} if undefined. * @throws RuntimeException if the conversion failed. */ protected <V> V getOptionalValue(JsonNode node, String fieldName, Class<V> type, V fallback) throws RuntimeException { V result = getValue(node, fieldName, type, false); if (result == null) { result = fallback; } return result; } /** * @param <V> the type to convert the requested value to. * @param node parent node to deserialize * @param fieldName the name of the JSON property to get the value from. * @param type the {@link Class} reflecting the type to convert the requested value to. * @param required {@code true} if the requested value has to be present, {@code false} otherwise (if optional). * @return requested value converted to the given {@code type} or {@code null} if undefined and {@code required} is * {@code true}. * @throws RuntimeException if {@code required} is {@code true} and the requested value is not present or if the * conversion failed. */ @SuppressWarnings("unchecked") protected <V> V getValue(JsonNode node, String fieldName, Class<V> type, boolean required) throws RuntimeException { V value = null; JsonNode childNode = node.get(fieldName); if (childNode != null) { if (!childNode.isNull()) { try { if (type == String.class) { value = type.cast(childNode.asText()); } else if (type == BigDecimal.class) { value = type.cast(new BigDecimal(childNode.asText())); } else if (type == BigInteger.class) { value = type.cast(new BigInteger(childNode.asText())); } else if (type == Date.class) { value = type.cast(Iso8601UtilImpl.getInstance().parseDate(childNode.asText())); } else if (type == Calendar.class) { value = type.cast(Iso8601UtilImpl.getInstance().parseCalendar(childNode.asText())); } else if (type == Boolean.class) { // types that may be primitive shall be casted explicitly as Class.cast does not work for primitive types. value = (V) Boolean.valueOf(childNode.booleanValue()); } else if (type == Integer.class) { value = (V) Integer.valueOf(childNode.asText()); } else if (type == Long.class) { value = (V) Long.valueOf(childNode.asText()); } else if (type == Double.class) { value = (V) Double.valueOf(childNode.asText()); } else if (type == Float.class) { value = (V) Float.valueOf(childNode.asText()); } else if (type == Short.class) { value = (V) Short.valueOf(childNode.asText()); } else if (type == Byte.class) { value = (V) Byte.valueOf(childNode.asText()); } else { throw new IllegalArgumentException("Unsupported value type " + type.getName()); } } catch (NumberFormatException e) { throw new IllegalArgumentException("Failed to convert value to type " + type.getName(), e); } } } if ((value == null) && (required)) { throw new IllegalStateException( "Deserialization failed due to missing " + type.getSimpleName() + " field " + fieldName + "!"); } return value; } @Override public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { JsonNode node = jp.getCodec().readTree(jp); return deserializeNode(node); } /** * @param node is the {@link JsonNode} with the value content to be deserialized * @return the deserialized java object */ protected abstract T deserializeNode(JsonNode node); }