Skip to content

Commit

Permalink
Fix #1211
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Apr 21, 2016
1 parent 5df9056 commit e9df815
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 39 deletions.
1 change: 1 addition & 0 deletions release-notes/VERSION
Expand Up @@ -19,6 +19,7 @@ Project: jackson-databind
#1182: Add the ability to specify the initial capacity of the ArrayNode #1182: Add the ability to specify the initial capacity of the ArrayNode
(suggested by Matt V, mveitas@github) (suggested by Matt V, mveitas@github)
#1187: Refactor `AtomicReferenceDeserializer` into `ReferenceTypeDeserializer` #1187: Refactor `AtomicReferenceDeserializer` into `ReferenceTypeDeserializer`
#1211: Change `JsonValueSerializer` to get `AnnotatedMethod`, not "raw" method


2.7.4 (not yet released) 2.7.4 (not yet released)


Expand Down
Expand Up @@ -114,7 +114,15 @@ public final Object call(Object[] args) throws Exception {
public final Object call1(Object arg) throws Exception { public final Object call1(Object arg) throws Exception {
return _method.invoke(null, arg); return _method.invoke(null, arg);
} }


public final Object callOn(Object pojo) throws Exception {
return _method.invoke(pojo);
}

public final Object callOnWith(Object pojo, Object... args) throws Exception {
return _method.invoke(pojo, args);
}

/* /*
/******************************************************** /********************************************************
/* AnnotatedMember impl /* AnnotatedMember impl
Expand Down Expand Up @@ -154,7 +162,7 @@ public Object getValue(Object pojo) throws IllegalArgumentException
+getFullName()+": "+e.getMessage(), e); +getFullName()+": "+e.getMessage(), e);
} }
} }

/* /*
/***************************************************** /*****************************************************
/* Extended API, generic /* Extended API, generic
Expand All @@ -170,7 +178,7 @@ public String getFullName() {
return getDeclaringClass().getName() + "#" + getName() + "(" return getDeclaringClass().getName() + "#" + getName() + "("
+getParameterCount()+" params)"; +getParameterCount()+" params)";
} }

public Class<?>[] getRawParameterTypes() public Class<?>[] getRawParameterTypes()
{ {
if (_paramClasses == null) { if (_paramClasses == null) {
Expand Down
Expand Up @@ -234,7 +234,7 @@ public JsonSerializer<Object> createKeySerializer(SerializationConfig config,
if (config.canOverrideAccessModifiers()) { if (config.canOverrideAccessModifiers()) {
ClassUtil.checkAndFixAccess(m, config.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS)); ClassUtil.checkAndFixAccess(m, config.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));
} }
ser = new JsonValueSerializer(m, delegate); ser = new JsonValueSerializer(am, delegate);
} else { } else {
ser = StdKeySerializers.getFallbackKeySerializer(config, keyType.getRawClass()); ser = StdKeySerializers.getFallbackKeySerializer(config, keyType.getRawClass());
} }
Expand Down Expand Up @@ -353,7 +353,7 @@ protected final JsonSerializer<?> findSerializerByAnnotations(SerializerProvider
ClassUtil.checkAndFixAccess(m, prov.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS)); ClassUtil.checkAndFixAccess(m, prov.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));
} }
JsonSerializer<Object> ser = findSerializerFromAnnotation(prov, valueMethod); JsonSerializer<Object> ser = findSerializerFromAnnotation(prov, valueMethod);
return new JsonValueSerializer(m, ser); return new JsonValueSerializer(valueMethod, ser);
} }
// No well-known annotations... // No well-known annotations...
return null; return null;
Expand Down
Expand Up @@ -2,15 +2,14 @@


import java.io.IOException; import java.io.IOException;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.Set; import java.util.Set;


import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JacksonStdImpl; import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitable; import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitable;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper; import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonStringFormatVisitor; import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonStringFormatVisitor;
Expand All @@ -36,8 +35,11 @@
public class JsonValueSerializer public class JsonValueSerializer
extends StdSerializer<Object> extends StdSerializer<Object>
implements ContextualSerializer, JsonFormatVisitable, SchemaAware implements ContextualSerializer, JsonFormatVisitable, SchemaAware
{ {
protected final Method _accessorMethod; /**
* @since 2.8 (was "plain" method before)
*/
protected final AnnotatedMethod _accessorMethod;


protected final JsonSerializer<Object> _valueSerializer; protected final JsonSerializer<Object> _valueSerializer;


Expand All @@ -62,11 +64,14 @@ public class JsonValueSerializer
* occurs if and only if the "value method" was annotated with * occurs if and only if the "value method" was annotated with
* {@link com.fasterxml.jackson.databind.annotation.JsonSerialize#using}), otherwise * {@link com.fasterxml.jackson.databind.annotation.JsonSerialize#using}), otherwise
* null * null
*
* @since 2.8 Earlier method took "raw" Method, but that does not work with access
* to information we need
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public JsonValueSerializer(Method valueMethod, JsonSerializer<?> ser) public JsonValueSerializer(AnnotatedMethod valueMethod, JsonSerializer<?> ser)
{ {
super(valueMethod.getReturnType(), false); super(valueMethod.getType());
_accessorMethod = valueMethod; _accessorMethod = valueMethod;
_valueSerializer = (JsonSerializer<Object>) ser; _valueSerializer = (JsonSerializer<Object>) ser;
_property = null; _property = null;
Expand Down Expand Up @@ -120,9 +125,8 @@ public JsonSerializer<?> createContextual(SerializerProvider provider,
* if not, we don't really know the actual type until we get the instance. * if not, we don't really know the actual type until we get the instance.
*/ */
// 10-Mar-2010, tatu: Except if static typing is to be used // 10-Mar-2010, tatu: Except if static typing is to be used
if (provider.isEnabled(MapperFeature.USE_STATIC_TYPING) JavaType t = _accessorMethod.getType();
|| Modifier.isFinal(_accessorMethod.getReturnType().getModifiers())) { if (provider.isEnabled(MapperFeature.USE_STATIC_TYPING) || t.isFinal()) {
JavaType t = provider.constructType(_accessorMethod.getGenericReturnType());
// false -> no need to cache // false -> no need to cache
/* 10-Mar-2010, tatu: Ideally we would actually separate out type /* 10-Mar-2010, tatu: Ideally we would actually separate out type
* serializer from value serializer; but, alas, there's no access * serializer from value serializer; but, alas, there's no access
Expand Down Expand Up @@ -155,7 +159,7 @@ public JsonSerializer<?> createContextual(SerializerProvider provider,
public void serialize(Object bean, JsonGenerator jgen, SerializerProvider prov) throws IOException public void serialize(Object bean, JsonGenerator jgen, SerializerProvider prov) throws IOException
{ {
try { try {
Object value = _accessorMethod.invoke(bean); Object value = _accessorMethod.getValue(bean);
if (value == null) { if (value == null) {
prov.defaultSerializeNull(jgen); prov.defaultSerializeNull(jgen);
return; return;
Expand Down Expand Up @@ -195,7 +199,7 @@ public void serializeWithType(Object bean, JsonGenerator jgen, SerializerProvide
// Regardless of other parts, first need to find value to serialize: // Regardless of other parts, first need to find value to serialize:
Object value = null; Object value = null;
try { try {
value = _accessorMethod.invoke(bean); value = _accessorMethod.getValue(bean);
// and if we got null, can also just write it directly // and if we got null, can also just write it directly
if (value == null) { if (value == null) {
provider.defaultSerializeNull(jgen); provider.defaultSerializeNull(jgen);
Expand Down Expand Up @@ -255,32 +259,25 @@ public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType t
throws JsonMappingException throws JsonMappingException
{ {
/* 27-Apr-2015, tatu: First things first; for JSON Schema introspection, /* 27-Apr-2015, tatu: First things first; for JSON Schema introspection,
* Enums are special, and unfortunately we will need to add special * Enum types that use `@JsonValue` are special (but NOT necessarily
* anything else that RETURNS an enum!)
* So we will need to add special
* handling here (see https://github.com/FasterXML/jackson-module-jsonSchema/issues/57 * handling here (see https://github.com/FasterXML/jackson-module-jsonSchema/issues/57
* for details). * for details).
*
* Note that meaning of JsonValue, then, is very different for Enums. Sigh.
*/ */
Class<?> decl = (typeHint == null) ? null : typeHint.getRawClass(); final JavaType type = _accessorMethod.getType();
if (decl == null) { Class<?> declaring = _accessorMethod.getDeclaringClass();
decl = _accessorMethod.getDeclaringClass(); if ((declaring != null) && declaring.isEnum()) {
} if (_acceptJsonFormatVisitorForEnum(visitor, typeHint, declaring)) {
if ((decl != null) && (decl.isEnum())) {
if (_acceptJsonFormatVisitorForEnum(visitor, typeHint, decl)) {
return; return;
} }
} }

JsonSerializer<Object> ser = _valueSerializer; JsonSerializer<Object> ser = _valueSerializer;
if (ser == null) { if (ser == null) {
if (typeHint == null) { ser = visitor.getProvider().findTypedValueSerializer(type, false, _property);
if (_property != null) { if (ser == null) { // can this ever occur?
typeHint = _property.getType();
}
if (typeHint == null) {
typeHint = visitor.getProvider().constructType(_handledType);
}
}
ser = visitor.getProvider().findTypedValueSerializer(typeHint, false, _property);
if (ser == null) {
visitor.expectAnyFormat(typeHint); visitor.expectAnyFormat(typeHint);
return; return;
} }
Expand All @@ -290,7 +287,7 @@ public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType t


/** /**
* Overridable helper method used for special case handling of schema information for * Overridable helper method used for special case handling of schema information for
* Enums * Enums.
* *
* @return True if method handled callbacks; false if not; in latter case caller will * @return True if method handled callbacks; false if not; in latter case caller will
* send default callbacks * send default callbacks
Expand All @@ -307,7 +304,10 @@ protected boolean _acceptJsonFormatVisitorForEnum(JsonFormatVisitorWrapper visit
Set<String> enums = new LinkedHashSet<String>(); Set<String> enums = new LinkedHashSet<String>();
for (Object en : enumType.getEnumConstants()) { for (Object en : enumType.getEnumConstants()) {
try { try {
enums.add(String.valueOf(_accessorMethod.invoke(en))); // 21-Apr-2016, tatu: This is convoluted to the max, but essentially we
// call `@JsonValue`-annotated accessor method on all Enum members,
// so it all "works out". To some degree.
enums.add(String.valueOf(_accessorMethod.callOn(en)));
} catch (Exception e) { } catch (Exception e) {
Throwable t = e; Throwable t = e;
while (t instanceof InvocationTargetException && t.getCause() != null) { while (t instanceof InvocationTargetException && t.getCause() != null) {
Expand All @@ -322,9 +322,8 @@ protected boolean _acceptJsonFormatVisitorForEnum(JsonFormatVisitorWrapper visit
stringVisitor.enumTypes(enums); stringVisitor.enumTypes(enums);
} }
return true; return true;

} }

protected boolean isNaturalTypeWithStdHandling(Class<?> rawType, JsonSerializer<?> ser) protected boolean isNaturalTypeWithStdHandling(Class<?> rawType, JsonSerializer<?> ser)
{ {
// First: do we have a natural type being handled? // First: do we have a natural type being handled?
Expand Down
Expand Up @@ -100,7 +100,8 @@ public void format(JsonValueFormat format) { }
public void testEnumWithJsonValue() throws Exception public void testEnumWithJsonValue() throws Exception
{ {
final Set<String> values = new TreeSet<String>(); final Set<String> values = new TreeSet<String>();
MAPPER.acceptJsonFormatVisitor(TestEnumWithJsonValue.class, new JsonFormatVisitorWrapper.Base() { MAPPER.acceptJsonFormatVisitor(TestEnumWithJsonValue.class,
new JsonFormatVisitorWrapper.Base() {
@Override @Override
public JsonStringFormatVisitor expectStringFormat(JavaType type) { public JsonStringFormatVisitor expectStringFormat(JavaType type) {
return new JsonStringFormatVisitor() { return new JsonStringFormatVisitor() {
Expand Down

0 comments on commit e9df815

Please sign in to comment.