Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle MalformedParameterizedTypeException in AnnotatedConstructor.getGenericParameterTypes(idx) #418

Closed
aantono opened this issue Mar 4, 2014 · 6 comments

Comments

@aantono
Copy link

aantono commented Mar 4, 2014

Currently the MalformedParameterizedTypeException is not being handled when trying to resolve the "creators" in POJOPropertiesCollector. This exception can be thrown by the JDK "Constructor" class when asking for "getGenericParameterTypes". This is typically happens if the JVM/JDK implementation does not think that the declared type can be instantiated (like having a List type [which is an interface] be declared as a constructor argument).

It seems that Jackson can handle List and Map types via other mechanisms, so maybe just ignoring those constructors that throw this exception is the best coarse of action and create the object using other (creatable) constructors or via direct field member setting.

@cowtowncoder
Copy link
Member

I think I'll need a unit test to show an example case; I have not seen this problem before.

It should be possible to handle all type declarations; and whether type is abstract or not should not be problematic for type resolution. It may be problem for later processing (depending on whether polymorphic type info is available), but should not fail at resolution phase.

Thank you for reporting the problem!

@aantono
Copy link
Author

aantono commented Mar 4, 2014

I can't seem to be able to produce a free-standing unit test. When I create a free-standing class, I don't get the exception anymore. But this is the exception trace I am getting:

The constructor signature that seems to cause this error looks like this:

public class Foo {
    public Foo(Scalar<Area> sizeOfRoom) {}
}

Class Scalar is a complex class destined to represent scalar values of any kind (via Generics types)

This is what that class looks like:

public class Scalar<Q extends javax.measure.quantity.Quantity> implements javax.measure.Measurable<Q>, Serializable {
    /**
     * Version Id used for serialization. Special care required if ever changed.
     */
    private static final long serialVersionUID = 2L;

    /**
     * The default tolerance value for the quantity.
     */
    private static final int DEFAULT_SCALE = 2;

    /**
     * Holds the amount value.
     */
    private final double _value;

    /**
     * Holds the unit.
     */
    private final Unit<Q> _unit;

    /**
     * The amount by which the magnitude of the Quantity can differ.
     */
    private final int _scale;

    /**
     * Creates a simple quantity of specified amount stated in the specified unit with the
     * default scale of 2 decimal places in the specified unit.
     * 
     * @param value the quantity amount stated in the specified unit.
     * @param unit  the value unit.
     * @throws IllegalArgumentException if <code>unit</code> is <code>null</code>
     */
    public Scalar(double value, Unit<Q> unit) {
        this(value, DEFAULT_SCALE, unit);
    }

    /**
     * Creates a simple quantity of specified amount and unit with the specified scale.
     * 
     * @param value the quantity amount stated in the specified unit.
     * @param scale the number of decimal places to consider when comparing or generating
     *            hashCodes.
     * @param unit  the value unit.
     * @throws IllegalArgumentException if the <code>scale &lt; 0</code> or if unit is <code>null</code>
     */
    public Scalar(double value, int scale, Unit<Q> unit) {
        if (null == unit) {
            throw new IllegalArgumentException("Unit cannot be null.");
        }
        if (scale < 0) {
            throw new IllegalArgumentException("Scale cannot be negative.");
        }
        _value = value;
        _scale = scale;
        _unit = unit;
    }

   .....
}
Caused by: java.lang.reflect.MalformedParameterizedTypeException
    at sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.validateConstructorArguments(ParameterizedTypeImpl.java:42)
    at sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.<init>(ParameterizedTypeImpl.java:35)
    at sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.make(ParameterizedTypeImpl.java:77)
    at sun.reflect.generics.factory.CoreReflectionFactory.makeParameterizedType(CoreReflectionFactory.java:86)
    at sun.reflect.generics.visitor.Reifier.visitClassTypeSignature(Reifier.java:122)
    at sun.reflect.generics.tree.ClassTypeSignature.accept(ClassTypeSignature.java:31)
    at sun.reflect.generics.repository.ConstructorRepository.getParameterTypes(ConstructorRepository.java:76)
    at java.lang.reflect.Constructor.getGenericParameterTypes(Constructor.java:238)
    at com.fasterxml.jackson.databind.introspect.AnnotatedConstructor.getGenericParameterType(AnnotatedConstructor.java:114)
    at com.fasterxml.jackson.databind.introspect.AnnotatedWithParams.getParameter(AnnotatedWithParams.java:119)
    at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._addCreators(POJOPropertiesCollector.java:436)
    at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.collect(POJOPropertiesCollector.java:235)
    at com.fasterxml.jackson.databind.introspect.BasicClassIntrospector.collectProperties(BasicClassIntrospector.java:142)
    at com.fasterxml.jackson.databind.introspect.BasicClassIntrospector.forSerialization(BasicClassIntrospector.java:68)
    at com.fasterxml.jackson.databind.introspect.BasicClassIntrospector.forSerialization(BasicClassIntrospector.java:11)
    at com.fasterxml.jackson.databind.SerializationConfig.introspect(SerializationConfig.java:530)
    at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.createSerializer(BeanSerializerFactory.java:133)
    at com.fasterxml.jackson.databind.SerializerProvider._createUntypedSerializer(SerializerProvider.java:1077)
    at com.fasterxml.jackson.databind.SerializerProvider._createAndCacheUntypedSerializer(SerializerProvider.java:1037)
    at com.fasterxml.jackson.databind.SerializerProvider.findPrimaryPropertySerializer(SerializerProvider.java:554)
    at com.fasterxml.jackson.databind.ser.impl.PropertySerializerMap.findAndAddPrimarySerializer(PropertySerializerMap.java:69)
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter._findAndAddDynamic(BeanPropertyWriter.java:706)
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:522)
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:632)
    ... 43 more

@aantono
Copy link
Author

aantono commented Mar 4, 2014

After further digging I think I can see what is causing this issue and why I was not able to reproduce it in a clean, stand-alone test. :(
The scalar library was compiled using the following javac -source=1.5 -target=jsr14, so even though the Generics are being used in the code, the generated bytecode is probably missing some of the type inference information due to being compiled with -target=jsr14 and that is what is causing the exception.

@cowtowncoder
Copy link
Member

Ah. And yes, since stack trace comes from within JDK, it's bit hard for Jackson to do much.

Although if that would make a difference, it'd be possible to catch this exception and change message, to suggest likely problem. Would this make sense?

@aantono
Copy link
Author

aantono commented Mar 4, 2014

Do you think it would be acceptable to just catch that exception at the source and ignore those constructors/types and fall back to use object creation by default constructor + fields, or fall back to the explicitly configured serializers for those types?

I have tried to provide my own Module with the pre-configured Serializer for the type, but this exception comes up at the very beginning before any of the custom stuff comes into play.

@cowtowncoder
Copy link
Member

As I said, I don't like hiding real problems under carpet; this tends to leave to mysterious failures, and users are puzzled by what seems like a bug. I don't see this as a good solution.

But you can disable creator introspection, or even all annotation introspection, which would avoid the problem. It would also make it impossible to use said annotations as downside.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants