| package org.codehaus.jackson.map.ser.std; |
| |
| import java.io.IOException; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Type; |
| |
| import org.codehaus.jackson.JsonGenerationException; |
| import org.codehaus.jackson.JsonGenerator; |
| import org.codehaus.jackson.JsonNode; |
| import org.codehaus.jackson.map.BeanProperty; |
| import org.codehaus.jackson.map.JsonMappingException; |
| import org.codehaus.jackson.map.JsonSerializer; |
| import org.codehaus.jackson.map.ResolvableSerializer; |
| import org.codehaus.jackson.map.SerializerProvider; |
| import org.codehaus.jackson.map.TypeSerializer; |
| import org.codehaus.jackson.map.annotate.JacksonStdImpl; |
| import org.codehaus.jackson.map.ser.impl.PropertySerializerMap; |
| import org.codehaus.jackson.map.type.ArrayType; |
| import org.codehaus.jackson.node.ObjectNode; |
| import org.codehaus.jackson.schema.JsonSchema; |
| import org.codehaus.jackson.schema.SchemaAware; |
| import org.codehaus.jackson.type.JavaType; |
| |
| /** |
| * Generic serializer for Object arrays (<code>Object[]</code>). |
| * |
| * @since 1.9 (moved from 'org.codehaus.jackson.map.ser.impl.ObjectArraySerializer') |
| */ |
| @JacksonStdImpl |
| public class ObjectArraySerializer |
| extends StdArraySerializers.ArraySerializerBase<Object[]> |
| implements ResolvableSerializer |
| { |
| /** |
| * Whether we are using static typing (using declared types, ignoring |
| * runtime type) or not for elements. |
| */ |
| protected final boolean _staticTyping; |
| |
| /** |
| * Declared type of element entries |
| */ |
| protected final JavaType _elementType; |
| |
| /** |
| * Value serializer to use, if it can be statically determined. |
| * |
| * @since 1.5 |
| */ |
| protected JsonSerializer<Object> _elementSerializer; |
| |
| /** |
| * If element type can not be statically determined, mapping from |
| * runtime type to serializer is handled using this object |
| * |
| * @since 1.7 |
| */ |
| protected PropertySerializerMap _dynamicSerializers; |
| |
| /** |
| * @deprecated since 1.8 |
| */ |
| @Deprecated |
| public ObjectArraySerializer(JavaType elemType, boolean staticTyping, |
| TypeSerializer vts, BeanProperty property) |
| { |
| this(elemType, staticTyping, vts, property, null); |
| } |
| |
| public ObjectArraySerializer(JavaType elemType, boolean staticTyping, |
| TypeSerializer vts, BeanProperty property, JsonSerializer<Object> elementSerializer) |
| { |
| super(Object[].class, vts, property); |
| _elementType = elemType; |
| _staticTyping = staticTyping; |
| _dynamicSerializers = PropertySerializerMap.emptyMap(); |
| _elementSerializer = elementSerializer; |
| } |
| |
| @Override |
| public ContainerSerializerBase<?> _withValueTypeSerializer(TypeSerializer vts) |
| { |
| return new ObjectArraySerializer(_elementType, _staticTyping, vts, _property, _elementSerializer); |
| } |
| |
| @Override |
| public void serializeContents(Object[] value, JsonGenerator jgen, SerializerProvider provider) |
| throws IOException, JsonGenerationException |
| { |
| final int len = value.length; |
| if (len == 0) { |
| return; |
| } |
| if (_elementSerializer != null) { |
| serializeContentsUsing(value, jgen, provider, _elementSerializer); |
| return; |
| } |
| if (_valueTypeSerializer != null) { |
| serializeTypedContents(value, jgen, provider); |
| return; |
| } |
| int i = 0; |
| Object elem = null; |
| try { |
| PropertySerializerMap serializers = _dynamicSerializers; |
| for (; i < len; ++i) { |
| elem = value[i]; |
| if (elem == null) { |
| provider.defaultSerializeNull(jgen); |
| continue; |
| } |
| Class<?> cc = elem.getClass(); |
| JsonSerializer<Object> serializer = serializers.serializerFor(cc); |
| if (serializer == null) { |
| // To fix [JACKSON-508] |
| if (_elementType.hasGenericTypes()) { |
| serializer = _findAndAddDynamic(serializers, |
| provider.constructSpecializedType(_elementType, cc), provider); |
| } else { |
| serializer = _findAndAddDynamic(serializers, cc, provider); |
| } |
| } |
| serializer.serialize(elem, jgen, provider); |
| } |
| } catch (IOException ioe) { |
| throw ioe; |
| } catch (Exception e) { |
| // [JACKSON-55] Need to add reference information |
| /* 05-Mar-2009, tatu: But one nasty edge is when we get |
| * StackOverflow: usually due to infinite loop. But that gets |
| * hidden within an InvocationTargetException... |
| */ |
| Throwable t = e; |
| while (t instanceof InvocationTargetException && t.getCause() != null) { |
| t = t.getCause(); |
| } |
| if (t instanceof Error) { |
| throw (Error) t; |
| } |
| throw JsonMappingException.wrapWithPath(t, elem, i); |
| } |
| } |
| |
| public void serializeContentsUsing(Object[] value, JsonGenerator jgen, SerializerProvider provider, |
| JsonSerializer<Object> ser) |
| throws IOException, JsonGenerationException |
| { |
| final int len = value.length; |
| final TypeSerializer typeSer = _valueTypeSerializer; |
| |
| int i = 0; |
| Object elem = null; |
| try { |
| for (; i < len; ++i) { |
| elem = value[i]; |
| if (elem == null) { |
| provider.defaultSerializeNull(jgen); |
| continue; |
| } |
| if (typeSer == null) { |
| ser.serialize(elem, jgen, provider); |
| } else { |
| ser.serializeWithType(elem, jgen, provider, typeSer); |
| } |
| } |
| } catch (IOException ioe) { |
| throw ioe; |
| } catch (Exception e) { |
| Throwable t = e; |
| while (t instanceof InvocationTargetException && t.getCause() != null) { |
| t = t.getCause(); |
| } |
| if (t instanceof Error) { |
| throw (Error) t; |
| } |
| throw JsonMappingException.wrapWithPath(t, elem, i); |
| } |
| } |
| |
| public void serializeTypedContents(Object[] value, JsonGenerator jgen, SerializerProvider provider) |
| throws IOException, JsonGenerationException |
| { |
| final int len = value.length; |
| final TypeSerializer typeSer = _valueTypeSerializer; |
| int i = 0; |
| Object elem = null; |
| try { |
| PropertySerializerMap serializers = _dynamicSerializers; |
| for (; i < len; ++i) { |
| elem = value[i]; |
| if (elem == null) { |
| provider.defaultSerializeNull(jgen); |
| continue; |
| } |
| Class<?> cc = elem.getClass(); |
| JsonSerializer<Object> serializer = serializers.serializerFor(cc); |
| if (serializer == null) { |
| serializer = _findAndAddDynamic(serializers, cc, provider); |
| } |
| serializer.serializeWithType(elem, jgen, provider, typeSer); |
| } |
| } catch (IOException ioe) { |
| throw ioe; |
| } catch (Exception e) { |
| Throwable t = e; |
| while (t instanceof InvocationTargetException && t.getCause() != null) { |
| t = t.getCause(); |
| } |
| if (t instanceof Error) { |
| throw (Error) t; |
| } |
| throw JsonMappingException.wrapWithPath(t, elem, i); |
| } |
| } |
| |
| @Override |
| public JsonNode getSchema(SerializerProvider provider, Type typeHint) |
| throws JsonMappingException |
| { |
| ObjectNode o = createSchemaNode("array", true); |
| if (typeHint != null) { |
| JavaType javaType = provider.constructType(typeHint); |
| if (javaType.isArrayType()) { |
| Class<?> componentType = ((ArrayType) javaType).getContentType().getRawClass(); |
| // 15-Oct-2010, tatu: We can't serialize plain Object.class; but what should it produce here? Untyped? |
| if (componentType == Object.class) { |
| o.put("items", JsonSchema.getDefaultSchemaNode()); |
| } else { |
| JsonSerializer<Object> ser = provider.findValueSerializer(componentType, _property); |
| JsonNode schemaNode = (ser instanceof SchemaAware) ? |
| ((SchemaAware) ser).getSchema(provider, null) : |
| JsonSchema.getDefaultSchemaNode(); |
| o.put("items", schemaNode); |
| } |
| } |
| } |
| return o; |
| } |
| |
| /** |
| * Need to get callback to resolve value serializer, if static typing |
| * is used (either being forced, or because value type is final) |
| */ |
| @Override |
| public void resolve(SerializerProvider provider) |
| throws JsonMappingException |
| { |
| if (_staticTyping && _elementSerializer == null) { |
| _elementSerializer = provider.findValueSerializer(_elementType, _property); |
| } |
| } |
| |
| /** |
| * @since 1.7 |
| */ |
| protected final JsonSerializer<Object> _findAndAddDynamic(PropertySerializerMap map, |
| Class<?> type, SerializerProvider provider) throws JsonMappingException |
| { |
| PropertySerializerMap.SerializerAndMapResult result = map.findAndAddSerializer(type, provider, _property); |
| // did we get a new map of serializers? If so, start using it |
| if (map != result.map) { |
| _dynamicSerializers = result.map; |
| } |
| return result.serializer; |
| } |
| |
| /** |
| * @since 1.8 |
| */ |
| protected final JsonSerializer<Object> _findAndAddDynamic(PropertySerializerMap map, |
| JavaType type, SerializerProvider provider) throws JsonMappingException |
| { |
| PropertySerializerMap.SerializerAndMapResult result = map.findAndAddSerializer(type, provider, _property); |
| // did we get a new map of serializers? If so, start using it |
| if (map != result.map) { |
| _dynamicSerializers = result.map; |
| } |
| return result.serializer; |
| } |
| |
| } |