OneBasedMonthDeserializer.java

package com.fasterxml.jackson.datatype.jsr310.deser;

import java.io.IOException;
import java.time.Month;

import com.fasterxml.jackson.core.JsonParser;

import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.deser.std.DelegatingDeserializer;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;

/**
 * @since 2.17
 */
public class OneBasedMonthDeserializer extends DelegatingDeserializer {
    private static final long serialVersionUID = 1L;

    public OneBasedMonthDeserializer(JsonDeserializer<?> defaultDeserializer) {
        super(defaultDeserializer);
    }

    @Override
    public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        switch (p.currentToken()) {
        case VALUE_NUMBER_INT:
            return _decodeMonth(p.getIntValue(), p);
        case VALUE_STRING:
            String monthSpec = p.getText();
            int oneBasedMonthNumber = _decodeNumber(monthSpec);
            if (oneBasedMonthNumber >= 0) {
                return _decodeMonth(oneBasedMonthNumber, p);
            }
            // Otherwise fall through to default handling
            break;
        default:
        }
        return getDelegatee().deserialize(p, ctxt);
    }

    /**
     * @return Numeric value of input text that represents a 1-digit or 2-digit number.
     *         Negative value in other cases (empty string, not a number, 3 or more digits).
     */
    private int _decodeNumber(String text) {
        int numValue;
        switch (text.length()) {
            case 1:
                char c = text.charAt(0);
                boolean cValid = ('0' <= c && c <= '9');
                numValue = cValid ? (c - '0') : -1;
                break;
            case 2:
                char c1 = text.charAt(0);
                char c2 = text.charAt(1);
                boolean c12valid = ('0' <= c1 && c1 <= '9' && '0' <= c2 && c2 <= '9');
                numValue = c12valid ? (10 * (c1 - '0') + (c2 - '0')) : -1;
                break;
            default:
                numValue = -1;
        }
        return numValue;
    }

    private Month _decodeMonth(int oneBasedMonthNumber, JsonParser parser) throws InvalidFormatException {
        if (Month.JANUARY.getValue() <= oneBasedMonthNumber && oneBasedMonthNumber <= Month.DECEMBER.getValue()) {
            return Month.of(oneBasedMonthNumber);
        }
        throw new InvalidFormatException(parser, "Month number " + oneBasedMonthNumber + " not allowed for 1-based Month.", oneBasedMonthNumber, Integer.class);
    }

    @Override
    protected JsonDeserializer<?> newDelegatingInstance(JsonDeserializer<?> newDelegatee) {
        return new OneBasedMonthDeserializer(newDelegatee);
    }
}