1 package com.fasterxml.jackson.databind.deser.impl; 2 3 import java.util.*; 4 5 import com.fasterxml.jackson.databind.DeserializationContext; 6 import com.fasterxml.jackson.databind.JavaType; 7 import com.fasterxml.jackson.databind.JsonDeserializer; 8 import com.fasterxml.jackson.databind.JsonMappingException; 9 import com.fasterxml.jackson.databind.deser.std.StdDelegatingDeserializer; 10 import com.fasterxml.jackson.databind.type.TypeFactory; 11 import com.fasterxml.jackson.databind.util.Converter; 12 13 /** 14 * Helper class used to contain logic for deserializing "special" containers 15 * from {@code java.util.Collections} and {@code java.util.Arrays}. This is needed 16 * because they do not have usable no-arguments constructor: however, are easy enough 17 * to deserialize using delegating deserializer. 18 * 19 * @since 2.9.4 20 */ 21 public abstract class JavaUtilCollectionsDeserializers 22 { 23 private final static int TYPE_SINGLETON_SET = 1; 24 private final static int TYPE_SINGLETON_LIST = 2; 25 private final static int TYPE_SINGLETON_MAP = 3; 26 27 private final static int TYPE_UNMODIFIABLE_SET = 4; 28 private final static int TYPE_UNMODIFIABLE_LIST = 5; 29 private final static int TYPE_UNMODIFIABLE_MAP = 6; 30 31 public final static int TYPE_AS_LIST = 7; 32 33 // 10-Jan-2018, tatu: There are a few "well-known" special containers in JDK too: 34 35 private final static Class<?> CLASS_AS_ARRAYS_LIST = Arrays.asList(null, null).getClass(); 36 37 private final static Class<?> CLASS_SINGLETON_SET; 38 private final static Class<?> CLASS_SINGLETON_LIST; 39 private final static Class<?> CLASS_SINGLETON_MAP; 40 41 private final static Class<?> CLASS_UNMODIFIABLE_SET; 42 private final static Class<?> CLASS_UNMODIFIABLE_LIST; 43 44 /* 02-Mar-2019, tatu: for [databind#2265], need to consider possible alternate type... 45 * which we essentially coerce into the other one 46 */ 47 private final static Class<?> CLASS_UNMODIFIABLE_LIST_ALIAS; 48 private final static Class<?> CLASS_UNMODIFIABLE_MAP; 49 50 static { 51 Set<?> set = Collections.singleton(Boolean.TRUE); 52 CLASS_SINGLETON_SET = set.getClass(); 53 CLASS_UNMODIFIABLE_SET = Collections.unmodifiableSet(set).getClass(); 54 55 List<?> list = Collections.singletonList(Boolean.TRUE); 56 CLASS_SINGLETON_LIST = list.getClass(); 57 CLASS_UNMODIFIABLE_LIST = Collections.unmodifiableList(list).getClass(); 58 // for [databind#2265] 59 CLASS_UNMODIFIABLE_LIST_ALIAS = Collections.unmodifiableList(new LinkedList<Object>()).getClass(); 60 61 Map<?,?> map = Collections.singletonMap("a", "b"); 62 CLASS_SINGLETON_MAP = map.getClass(); 63 CLASS_UNMODIFIABLE_MAP = Collections.unmodifiableMap(map).getClass(); 64 } 65 findForCollection(DeserializationContext ctxt, JavaType type)66 public static JsonDeserializer<?> findForCollection(DeserializationContext ctxt, 67 JavaType type) 68 throws JsonMappingException 69 { 70 JavaUtilCollectionsConverter conv; 71 72 // 10-Jan-2017, tatu: Some types from `java.util.Collections`/`java.util.Arrays` need bit of help... 73 if (type.hasRawClass(CLASS_AS_ARRAYS_LIST)) { 74 conv = converter(TYPE_AS_LIST, type, List.class); 75 } else if (type.hasRawClass(CLASS_SINGLETON_LIST)) { 76 conv = converter(TYPE_SINGLETON_LIST, type, List.class); 77 } else if (type.hasRawClass(CLASS_SINGLETON_SET)) { 78 conv = converter(TYPE_SINGLETON_SET, type, Set.class); 79 // [databind#2265]: we may have another impl type for unmodifiable Lists, check both 80 } else if (type.hasRawClass(CLASS_UNMODIFIABLE_LIST) || type.hasRawClass(CLASS_UNMODIFIABLE_LIST_ALIAS)) { 81 conv = converter(TYPE_UNMODIFIABLE_LIST, type, List.class); 82 } else if (type.hasRawClass(CLASS_UNMODIFIABLE_SET)) { 83 conv = converter(TYPE_UNMODIFIABLE_SET, type, Set.class); 84 } else { 85 return null; 86 } 87 return new StdDelegatingDeserializer<Object>(conv); 88 } 89 findForMap(DeserializationContext ctxt, JavaType type)90 public static JsonDeserializer<?> findForMap(DeserializationContext ctxt, 91 JavaType type) 92 throws JsonMappingException 93 { 94 JavaUtilCollectionsConverter conv; 95 96 // 10-Jan-2017, tatu: Some types from `java.util.Collections`/`java.util.Arrays` need bit of help... 97 if (type.hasRawClass(CLASS_SINGLETON_MAP)) { 98 conv = converter(TYPE_SINGLETON_MAP, type, Map.class); 99 } else if (type.hasRawClass(CLASS_UNMODIFIABLE_MAP)) { 100 conv = converter(TYPE_UNMODIFIABLE_MAP, type, Map.class); 101 } else { 102 return null; 103 } 104 return new StdDelegatingDeserializer<Object>(conv); 105 } 106 converter(int kind, JavaType concreteType, Class<?> rawSuper)107 static JavaUtilCollectionsConverter converter(int kind, 108 JavaType concreteType, Class<?> rawSuper) 109 { 110 return new JavaUtilCollectionsConverter(kind, concreteType.findSuperType(rawSuper)); 111 } 112 113 /** 114 * Implementation used for converting from various generic container 115 * types ({@link java.util.Set}, {@link java.util.List}, {@link java.util.Map}) 116 * into more specific implementations accessible via {@code java.util.Collections}. 117 */ 118 private static class JavaUtilCollectionsConverter implements Converter<Object,Object> 119 { 120 private final JavaType _inputType; 121 122 private final int _kind; 123 JavaUtilCollectionsConverter(int kind, JavaType inputType)124 private JavaUtilCollectionsConverter(int kind, JavaType inputType) { 125 _inputType = inputType; 126 _kind = kind; 127 } 128 129 @Override convert(Object value)130 public Object convert(Object value) { 131 if (value == null) { // is this legal to get? 132 return null; 133 } 134 135 switch (_kind) { 136 case TYPE_SINGLETON_SET: 137 { 138 Set<?> set = (Set<?>) value; 139 _checkSingleton(set.size()); 140 return Collections.singleton(set.iterator().next()); 141 } 142 case TYPE_SINGLETON_LIST: 143 { 144 List<?> list = (List<?>) value; 145 _checkSingleton(list.size()); 146 return Collections.singletonList(list.get(0)); 147 } 148 case TYPE_SINGLETON_MAP: 149 { 150 Map<?,?> map = (Map<?,?>) value; 151 _checkSingleton(map.size()); 152 Map.Entry<?,?> entry = map.entrySet().iterator().next(); 153 return Collections.singletonMap(entry.getKey(), entry.getValue()); 154 } 155 156 case TYPE_UNMODIFIABLE_SET: 157 return Collections.unmodifiableSet((Set<?>) value); 158 case TYPE_UNMODIFIABLE_LIST: 159 return Collections.unmodifiableList((List<?>) value); 160 case TYPE_UNMODIFIABLE_MAP: 161 return Collections.unmodifiableMap((Map<?,?>) value); 162 163 case TYPE_AS_LIST: 164 default: 165 // Here we do not actually care about impl type, just return List as-is: 166 return value; 167 } 168 } 169 170 @Override getInputType(TypeFactory typeFactory)171 public JavaType getInputType(TypeFactory typeFactory) { 172 return _inputType; 173 } 174 175 @Override getOutputType(TypeFactory typeFactory)176 public JavaType getOutputType(TypeFactory typeFactory) { 177 // we don't actually care, so: 178 return _inputType; 179 } 180 _checkSingleton(int size)181 private void _checkSingleton(int size) { 182 if (size != 1) { 183 // not the best error ever but... has to do 184 throw new IllegalArgumentException("Can not deserialize Singleton container from "+size+" entries"); 185 } 186 } 187 } 188 189 } 190