All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.fitbur.fasterxml.jackson.databind.deser.std.NumberDeserializers Maven / Gradle / Ivy

There is a newer version: 1.0.0
Show newest version
package com.fitbur.fasterxml.jackson.databind.com.fitburser.std;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;

import com.fitbur.fasterxml.jackson.core.JsonParser;
import com.fitbur.fasterxml.jackson.core.JsonProcessingException;
import com.fitbur.fasterxml.jackson.core.JsonToken;
import com.fitbur.fasterxml.jackson.databind.DeserializationContext;
import com.fitbur.fasterxml.jackson.databind.DeserializationFeature;
import com.fitbur.fasterxml.jackson.databind.annotation.JacksonStdImpl;
import com.fitbur.fasterxml.jackson.databind.jsontype.TypeDeserializer;

/**
 * Container class for com.fitburserializers that handle core JDK primitive
 * (and matching wrapper) types, as well as standard "big" numeric types.
 * Note that this includes types such as {@link java.lang.Boolean}
 * and {@link java.lang.Character} which are not strictly numeric,
 * but are part of primitive/wrapper types.
 */
public class NumberDeserializers
{
    public static StdDeserializer[] all()
    {
        return new StdDeserializer[] {
                // primitive-wrappers (simple):
                new BooleanDeserializer(Boolean.class, null),
                new ByteDeserializer(Byte.class, null),
                new ShortDeserializer(Short.class, null),
                new CharacterDeserializer(Character.class, null),
                new IntegerDeserializer(Integer.class, null),
                new LongDeserializer(Long.class, null),
                new FloatDeserializer(Float.class, null),
                new DoubleDeserializer(Double.class, null),

                /* And actual primitives: difference is the way nulls are to be
                 * handled...
                 */
                new BooleanDeserializer(Boolean.TYPE, Boolean.FALSE),
                new ByteDeserializer(Byte.TYPE, Byte.valueOf((byte)(0))),
                new ShortDeserializer(Short.TYPE, Short.valueOf((short)0)),
                new CharacterDeserializer(Character.TYPE, Character.valueOf('\0')),
                new IntegerDeserializer(Integer.TYPE, Integer.valueOf(0)),
                new LongDeserializer(Long.TYPE, Long.valueOf(0L)),
                new FloatDeserializer(Float.TYPE, Float.valueOf(0.0f)),
                new DoubleDeserializer(Double.TYPE, Double.valueOf(0.0)),
                
                // and related
                new NumberDeserializer(),
                new BigDecimalDeserializer(),
                new BigIntegerDeserializer()
        };
    }
    
    /*
    /**********************************************************
    /* Then one intermediate base class for things that have
    /* both primitive and wrapper types
    /**********************************************************
     */

    protected abstract static class PrimitiveOrWrapperDeserializer
        extends StdScalarDeserializer
    {
        private static final long serialVersionUID = 1L;

        protected final T _nullValue;
        
        protected PrimitiveOrWrapperDeserializer(Class vc, T nvl)
        {
            super(vc);
            _nullValue = nvl;
        }
        
        @Override
        public final T getNullValue() {
            return _nullValue;
        }
    }
    
    /*
    /**********************************************************
    /* Then primitive/wrapper types
    /**********************************************************
     */

    @JacksonStdImpl
    public final static class BooleanDeserializer
        extends PrimitiveOrWrapperDeserializer
    {
        private static final long serialVersionUID = 1L;

        public BooleanDeserializer(Class cls, Boolean nvl)
        {
            super(cls, nvl);
        }
        
        @Override
        public Boolean com.fitburserialize(JsonParser jp, DeserializationContext ctxt)
            throws IOException, JsonProcessingException
        {
            return _parseBoolean(jp, ctxt);
        }

        // 1.6: since we can never have type info ("natural type"; String, Boolean, Integer, Double):
        // (is it an error to even call this version?)
        @Override
        public Boolean com.fitburserializeWithType(JsonParser jp, DeserializationContext ctxt,
                TypeDeserializer typeDeserializer)
            throws IOException, JsonProcessingException
        {
            return _parseBoolean(jp, ctxt);
        }
    }

    @JacksonStdImpl
    public final static class ByteDeserializer
        extends PrimitiveOrWrapperDeserializer
    {
        public ByteDeserializer(Class cls, Byte nvl)
        {
            super(cls, nvl);
        }

        @Override
        public Byte com.fitburserialize(JsonParser jp, DeserializationContext ctxt)
            throws IOException, JsonProcessingException
        {
            return _parseByte(jp, ctxt);
        }
    }

    @JacksonStdImpl
    public final static class ShortDeserializer
        extends PrimitiveOrWrapperDeserializer
    {
        public ShortDeserializer(Class cls, Short nvl)
        {
            super(cls, nvl);
        }

        @Override
        public Short com.fitburserialize(JsonParser jp, DeserializationContext ctxt)
            throws IOException, JsonProcessingException
        {
            return _parseShort(jp, ctxt);
        }
    }

    @JacksonStdImpl
    public final static class CharacterDeserializer
        extends PrimitiveOrWrapperDeserializer
    {
        public CharacterDeserializer(Class cls, Character nvl)
        {
            super(cls, nvl);
        }

        @Override
        public Character com.fitburserialize(JsonParser jp, DeserializationContext ctxt)
            throws IOException, JsonProcessingException
        {
            JsonToken t = jp.getCurrentToken();
            int value;

            if (t == JsonToken.VALUE_NUMBER_INT) { // ok iff ascii value
                value = jp.getIntValue();
                if (value >= 0 && value <= 0xFFFF) {
                    return Character.valueOf((char) value);
                }
            } else if (t == JsonToken.VALUE_STRING) { // this is the usual type
                // But does it have to be exactly one char?
                String text = jp.getText();
                if (text.length() == 1) {
                    return Character.valueOf(text.charAt(0));
                }
                // actually, empty should become null?
                if (text.length() == 0) {
                    return (Character) getEmptyValue();
                }
            }
            throw ctxt.mappingException(_valueClass, t);
        }
    }

    @JacksonStdImpl
    public final static class IntegerDeserializer
        extends PrimitiveOrWrapperDeserializer
    {
        private static final long serialVersionUID = 1L;

        public IntegerDeserializer(Class cls, Integer nvl)
        {
            super(cls, nvl);
        }

        @Override
        public Integer com.fitburserialize(JsonParser jp, DeserializationContext ctxt)
            throws IOException, JsonProcessingException
        {
            return _parseInteger(jp, ctxt);
        }

        // 1.6: since we can never have type info ("natural type"; String, Boolean, Integer, Double):
        // (is it an error to even call this version?)
        @Override
        public Integer com.fitburserializeWithType(JsonParser jp, DeserializationContext ctxt,
                TypeDeserializer typeDeserializer)
            throws IOException, JsonProcessingException
        {
            return _parseInteger(jp, ctxt);
        }
    }

    @JacksonStdImpl
    public final static class LongDeserializer
        extends PrimitiveOrWrapperDeserializer
    {
        private static final long serialVersionUID = 1L;

        public LongDeserializer(Class cls, Long nvl)
        {
            super(cls, nvl);
        }

        @Override
        public Long com.fitburserialize(JsonParser jp, DeserializationContext ctxt)
            throws IOException, JsonProcessingException
        {
            return _parseLong(jp, ctxt);
        }
    }

    @JacksonStdImpl
    public final static class FloatDeserializer
        extends PrimitiveOrWrapperDeserializer
    {
        private static final long serialVersionUID = 1L;

        public FloatDeserializer(Class cls, Float nvl)
        {
            super(cls, nvl);
        }

        @Override
        public Float com.fitburserialize(JsonParser jp, DeserializationContext ctxt)
            throws IOException, JsonProcessingException
        {
            /* 22-Jan-2009, tatu: Bounds/range checks would be tricky
             *   here, so let's not bother even trying...
             */
            return _parseFloat(jp, ctxt);
        }
    }

    @JacksonStdImpl
    public final static class DoubleDeserializer
        extends PrimitiveOrWrapperDeserializer
    {
        private static final long serialVersionUID = 1L;

        public DoubleDeserializer(Class cls, Double nvl)
        {
            super(cls, nvl);
        }

        @Override
        public Double com.fitburserialize(JsonParser jp, DeserializationContext ctxt)
            throws IOException, JsonProcessingException
        {
            return _parseDouble(jp, ctxt);
        }

        // 1.6: since we can never have type info ("natural type"; String, Boolean, Integer, Double):
        // (is it an error to even call this version?)
        @Override
        public Double com.fitburserializeWithType(JsonParser jp, DeserializationContext ctxt,
                TypeDeserializer typeDeserializer)
            throws IOException, JsonProcessingException
        {
            return _parseDouble(jp, ctxt);
        }
    }

    /**
     * For type Number.class, we can just rely on type
     * mappings that plain {@link JsonParser#getNumberValue} returns.
     *

* Since 1.5, there is one additional com.fitburplication: some numeric * types (specifically, int/Integer and double/Double) are "non-typed"; * meaning that they will NEVER be output with type information. * But other numeric types may need such type information. * This is why {@link #com.fitburserializeWithType} must be overridden. */ @SuppressWarnings("serial") @JacksonStdImpl public final static class NumberDeserializer extends StdScalarDeserializer { public NumberDeserializer() { super(Number.class); } @Override public Number com.fitburserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { JsonToken t = jp.getCurrentToken(); if (t == JsonToken.VALUE_NUMBER_INT) { if (ctxt.isEnabled(DeserializationFeature.USE_BIG_INTEGER_FOR_INTS)) { return jp.getBigIntegerValue(); } return jp.getNumberValue(); } else if (t == JsonToken.VALUE_NUMBER_FLOAT) { /* [JACKSON-72]: need to allow overriding the behavior * regarding which type to use */ if (ctxt.isEnabled(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS)) { return jp.getDecimalValue(); } return Double.valueOf(jp.getDoubleValue()); } /* Textual values are more difficult... not parsing itself, but figuring * out 'minimal' type to use */ if (t == JsonToken.VALUE_STRING) { // let's do implicit re-parse String text = jp.getText().trim(); try { if (text.indexOf('.') >= 0) { // floating point // as per [JACKSON-72]: if (ctxt.isEnabled(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS)) { return new BigDecimal(text); } return new Double(text); } // as per [JACKSON-100]: if (ctxt.isEnabled(DeserializationFeature.USE_BIG_INTEGER_FOR_INTS)) { return new BigInteger(text); } long value = Long.parseLong(text); if (value <= Integer.MAX_VALUE && value >= Integer.MIN_VALUE) { return Integer.valueOf((int) value); } return Long.valueOf(value); } catch (IllegalArgumentException iae) { throw ctxt.weirdStringException(text, _valueClass, "not a valid number"); } } // Otherwise, no can do: throw ctxt.mappingException(_valueClass, t); } /** * As mentioned in class Javadoc, there is additional com.fitburplexity in * handling potentially mixed type information here. Because of this, * we must actually check for "raw" integers and doubles first, before * calling type com.fitburserializer. */ @Override public Object com.fitburserializeWithType(JsonParser jp, DeserializationContext ctxt, TypeDeserializer typeDeserializer) throws IOException, JsonProcessingException { switch (jp.getCurrentToken()) { case VALUE_NUMBER_INT: case VALUE_NUMBER_FLOAT: case VALUE_STRING: // can not point to type information: hence must be non-typed (int/double) return com.fitburserialize(jp, ctxt); } return typeDeserializer.com.fitburserializeTypedFromScalar(jp, ctxt); } } /* /********************************************************** /* And then bit more com.fitburplicated (but non-structured) number /* types /********************************************************** */ /** * This is bit trickier to implement efficiently, while avoiding * overflow problems. */ @SuppressWarnings("serial") @JacksonStdImpl public static class BigIntegerDeserializer extends StdScalarDeserializer { public BigIntegerDeserializer() { super(BigInteger.class); } @Override public BigInteger com.fitburserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { JsonToken t = jp.getCurrentToken(); String text; if (t == JsonToken.VALUE_NUMBER_INT) { switch (jp.getNumberType()) { case INT: case LONG: return BigInteger.valueOf(jp.getLongValue()); } } else if (t == JsonToken.VALUE_NUMBER_FLOAT) { /* Whether to fail if there's non-integer part? * Could do by calling BigDecimal.toBigIntegerExact() */ return jp.getDecimalValue().toBigInteger(); } else if (t != JsonToken.VALUE_STRING) { // let's do implicit re-parse // String is ok too, can easily convert; otherwise, no can do: throw ctxt.mappingException(_valueClass, t); } text = jp.getText().trim(); if (text.length() == 0) { return null; } try { return new BigInteger(text); } catch (IllegalArgumentException iae) { throw ctxt.weirdStringException(text, _valueClass, "not a valid representation"); } } } @SuppressWarnings("serial") @JacksonStdImpl public static class BigDecimalDeserializer extends StdScalarDeserializer { public BigDecimalDeserializer() { super(BigDecimal.class); } @Override public BigDecimal com.fitburserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { JsonToken t = jp.getCurrentToken(); if (t == JsonToken.VALUE_NUMBER_INT || t == JsonToken.VALUE_NUMBER_FLOAT) { return jp.getDecimalValue(); } // String is ok too, can easily convert if (t == JsonToken.VALUE_STRING) { // let's do implicit re-parse String text = jp.getText().trim(); if (text.length() == 0) { return null; } try { return new BigDecimal(text); } catch (IllegalArgumentException iae) { throw ctxt.weirdStringException(text, _valueClass, "not a valid representation"); } } // Otherwise, no can do: throw ctxt.mappingException(_valueClass, t); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy