package com.fasterxml.jackson.databind.deser.std;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Locale;
import java.util.UUID;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.io.NumberInput;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;
import com.fasterxml.jackson.databind.util.ClassUtil;
import com.fasterxml.jackson.databind.util.EnumResolver;
/**
* Base class for simple key deserializers.
*/
public abstract class StdKeyDeserializer
extends KeyDeserializer
{
final protected Class<?> _keyClass;
protected StdKeyDeserializer(Class<?> cls) { _keyClass = cls; }
@Override
public final Object deserializeKey(String key, DeserializationContext ctxt)
throws IOException, JsonProcessingException
{
if (key == null) { // is this even legal call?
return null;
}
try {
Object result = _parse(key, ctxt);
if (result != null) {
return result;
}
} catch (Exception re) {
throw ctxt.weirdKeyException(_keyClass, key, "not a valid representation: "+re.getMessage());
}
if (_keyClass.isEnum() && ctxt.getConfig().isEnabled(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL)) {
return null;
}
throw ctxt.weirdKeyException(_keyClass, key, "not a valid representation");
}
public Class<?> getKeyClass() { return _keyClass; }
protected abstract Object _parse(String key, DeserializationContext ctxt) throws Exception;
/*
/**********************************************************
/* Helper methods for sub-classes
/**********************************************************
*/
protected int _parseInt(String key) throws IllegalArgumentException
{
return Integer.parseInt(key);
}
protected long _parseLong(String key) throws IllegalArgumentException
{
return Long.parseLong(key);
}
protected double _parseDouble(String key) throws IllegalArgumentException
{
return NumberInput.parseDouble(key);
}
/*
/**********************************************************
/* First: the standard "String as String" deserializer
/**********************************************************
*/
@JacksonStdImpl
final static class StringKD extends StdKeyDeserializer
{
private final static StringKD sString = new StringKD(String.class);
private final static StringKD sObject = new StringKD(Object.class);
private StringKD(Class<?> nominalType) { super(nominalType); }
public static StringKD forType(Class<?> nominalType)
{
if (nominalType == String.class) {
return sString;
}
if (nominalType == Object.class) {
return sObject;
}
return new StringKD(nominalType);
}
@Override
public String _parse(String key, DeserializationContext ctxt) throws JsonMappingException {
return key;
}
}
/*
/**********************************************************
/* Key deserializer implementations; wrappers
/**********************************************************
*/
@JacksonStdImpl
final static class BoolKD extends StdKeyDeserializer
{
BoolKD() { super(Boolean.class); }
@Override
public Boolean _parse(String key, DeserializationContext ctxt) throws JsonMappingException
{
if ("true".equals(key)) {
return Boolean.TRUE;
}
if ("false".equals(key)) {
return Boolean.FALSE;
}
throw ctxt.weirdKeyException(_keyClass, key, "value not 'true' or 'false'");
}
}
@JacksonStdImpl
final static class ByteKD extends StdKeyDeserializer
{
ByteKD() { super(Byte.class); }
@Override
public Byte _parse(String key, DeserializationContext ctxt) throws JsonMappingException
{
int value = _parseInt(key);
// as per [JACKSON-804], allow range up to 255, inclusive
if (value < Byte.MIN_VALUE || value > 255) {
throw ctxt.weirdKeyException(_keyClass, key, "overflow, value can not be represented as 8-bit value");
}
return Byte.valueOf((byte) value);
}
}
@JacksonStdImpl
final static class ShortKD extends StdKeyDeserializer
{
ShortKD() { super(Integer.class); }
@Override
public Short _parse(String key, DeserializationContext ctxt) throws JsonMappingException
{
int value = _parseInt(key);
if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
throw ctxt.weirdKeyException(_keyClass, key, "overflow, value can not be represented as 16-bit value");
}
return Short.valueOf((short) value);
}
}
/**
* Dealing with Characters is bit trickier: let's assume it must be a String, and that
* Unicode numeric value is never used.
*/
@JacksonStdImpl
final static class CharKD extends StdKeyDeserializer
{
CharKD() { super(Character.class); }
@Override
public Character _parse(String key, DeserializationContext ctxt) throws JsonMappingException
{
if (key.length() == 1) {
return Character.valueOf(key.charAt(0));
}
throw ctxt.weirdKeyException(_keyClass, key, "can only convert 1-character Strings");
}
}
@JacksonStdImpl
final static class IntKD extends StdKeyDeserializer
{
IntKD() { super(Integer.class); }
@Override
public Integer _parse(String key, DeserializationContext ctxt) throws JsonMappingException
{
return _parseInt(key);
}
}
@JacksonStdImpl
final static class LongKD extends StdKeyDeserializer
{
LongKD() { super(Long.class); }
@Override
public Long _parse(String key, DeserializationContext ctxt) throws JsonMappingException
{
return _parseLong(key);
}
}
@JacksonStdImpl
final static class DoubleKD extends StdKeyDeserializer
{
DoubleKD() { super(Double.class); }
@Override
public Double _parse(String key, DeserializationContext ctxt) throws JsonMappingException
{
return _parseDouble(key);
}
}
@JacksonStdImpl
final static class FloatKD extends StdKeyDeserializer
{
FloatKD() { super(Float.class); }
@Override
public Float _parse(String key, DeserializationContext ctxt) throws JsonMappingException
{
/* 22-Jan-2009, tatu: Bounds/range checks would be tricky
* here, so let's not bother even trying...
*/
return Float.valueOf((float) _parseDouble(key));
}
}
@JacksonStdImpl
final static class LocaleKD extends StdKeyDeserializer {
protected JdkDeserializers.LocaleDeserializer _localeDeserializer;
LocaleKD() { super(Locale.class); _localeDeserializer = new JdkDeserializers.LocaleDeserializer();}
@Override
protected Locale _parse(String key, DeserializationContext ctxt) throws JsonMappingException {
try {
return _localeDeserializer._deserialize(key,ctxt);
} catch (IOException e) {
throw ctxt.weirdKeyException(_keyClass, key, "unable to parse key as locale");
}
}
}
/*
/**********************************************************
/* Key deserializer implementations; other
/**********************************************************
*/
/**
* Key deserializer that wraps a "regular" deserializer (but one
* that must recognize FIELD_NAMEs as text!) to reuse existing
* handlers as key handlers.
*/
final static class DelegatingKD extends KeyDeserializer // note: NOT the std one
{
final protected Class<?> _keyClass;
protected final JsonDeserializer<?> _delegate;
protected DelegatingKD(Class<?> cls, JsonDeserializer<?> deser) {
_keyClass = cls;
_delegate = deser;
}
@Override
public final Object deserializeKey(String key, DeserializationContext ctxt)
throws IOException, JsonProcessingException
{
if (key == null) { // is this even legal call?
return null;
}
try {
// Ugh... should not have to give parser which may or may not be correct one...
Object result = _delegate.deserialize(ctxt.getParser(), ctxt);
if (result != null) {
return result;
}
} catch (Exception re) {
throw ctxt.weirdKeyException(_keyClass, key, "not a valid representation: "+re.getMessage());
}
throw ctxt.weirdKeyException(_keyClass, key, "not a valid representation");
}
public Class<?> getKeyClass() { return _keyClass; }
}
@JacksonStdImpl
final static class EnumKD extends StdKeyDeserializer
{
protected final EnumResolver<?> _resolver;
protected final AnnotatedMethod _factory;
protected EnumKD(EnumResolver<?> er, AnnotatedMethod factory) {
super(er.getEnumClass());
_resolver = er;
_factory = factory;
}
@Override
public Object _parse(String key, DeserializationContext ctxt) throws JsonMappingException
{
if (_factory != null) {
try {
return _factory.call1(key);
} catch (Exception e) {
ClassUtil.unwrapAndThrowAsIAE(e);
}
}
Enum<?> e = _resolver.findEnum(key);
if (e == null && !ctxt.getConfig().isEnabled(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL)) {
throw ctxt.weirdKeyException(_keyClass, key, "not one of values for Enum class");
}
return e;
}
}
/**
* Key deserializer that calls a single-string-arg constructor
* to instantiate desired key type.
*/
final static class StringCtorKeyDeserializer extends StdKeyDeserializer
{
protected final Constructor<?> _ctor;
public StringCtorKeyDeserializer(Constructor<?> ctor) {
super(ctor.getDeclaringClass());
_ctor = ctor;
}
@Override
public Object _parse(String key, DeserializationContext ctxt) throws Exception
{
return _ctor.newInstance(key);
}
}
/**
* Key deserializer that calls a static no-args factory method
* to instantiate desired key type.
*/
final static class StringFactoryKeyDeserializer extends StdKeyDeserializer
{
final Method _factoryMethod;
public StringFactoryKeyDeserializer(Method fm) {
super(fm.getDeclaringClass());
_factoryMethod = fm;
}
@Override
public Object _parse(String key, DeserializationContext ctxt) throws Exception
{
return _factoryMethod.invoke(null, key);
}
}
// as per [JACKSON-657]
@JacksonStdImpl
final static class DateKD extends StdKeyDeserializer
{
protected DateKD() {
super(java.util.Date.class);
}
@Override
public Object _parse(String key, DeserializationContext ctxt)
throws IllegalArgumentException, JsonMappingException
{
return ctxt.parseDate(key);
}
}
// as per [JACKSON-657]
@JacksonStdImpl
final static class CalendarKD extends StdKeyDeserializer
{
protected CalendarKD() {
super(java.util.Calendar.class);
}
@Override
public Object _parse(String key, DeserializationContext ctxt)
throws IllegalArgumentException, JsonMappingException
{
java.util.Date date = ctxt.parseDate(key);
return (date == null) ? null : ctxt.constructCalendar(date);
}
}
// as per [JACKSON-726]
@JacksonStdImpl
final static class UuidKD extends StdKeyDeserializer
{
protected UuidKD() {
super(UUID.class);
}
@Override
public Object _parse(String key, DeserializationContext ctxt)
throws IllegalArgumentException, JsonMappingException
{
return UUID.fromString(key);
}
}
}