question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Unexpected InvalidTypeIdException when parsing XML to POJO containing nested List<> , custom `TypeIdResolver`

See original GitHub issue

XML Parsing fails with the complain that type id is missing, even when it is defined in the input xml

When ‘uid’ attribute is completely removed from the input xml, then the parsing works.

Java Code where problem can be reproduced with jackson-dataformat-xml 2.11.2

package com.temp;

import java.io.IOException;
import java.util.List;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.DatabindContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.annotation.JsonTypeIdResolver;
import com.fasterxml.jackson.databind.jsontype.impl.TypeIdResolverBase;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;

public class AutoParser {
    public static void main(String[] args) throws Exception {

        String xml = "" +
                "<Auto>\n" +
                "    <Object uid=\"1\" type=\"Engine\">\n" +
                "        <Object uid=\"2\" type=\"Chassis\"></Object>\n" +
                "        <Object uid=\"3\" type=\"Motor\"></Object>\n" +
                "    </Object>\n" +
                "    <Object uid=\"4\" type=\"Body\"></Object>\n" +
                "</Auto>";

        XmlMapper xmlMapper = new XmlMapper();
        Auto auto = xmlMapper.readValue(xml, Auto.class);
        xmlMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
        System.out.println(xmlMapper.writeValueAsString(auto));
    }
}

class Auto {

    @JacksonXmlProperty(localName = "Object")
    @JacksonXmlElementWrapper(useWrapping = false)
    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    List<CarParts> carParts;
}

@JsonTypeIdResolver(CarPartsResolver.class)
@JsonTypeInfo(use = JsonTypeInfo.Id.CUSTOM, include = JsonTypeInfo.As.PROPERTY, property = "type")
abstract class CarParts {

    @JacksonXmlProperty(isAttribute = true) // The is triggering the issue.
    String uid;

    @JacksonXmlProperty(localName = "Object")
    @JacksonXmlElementWrapper(useWrapping = false)
    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    List<CarParts> carParts;
}

class Engine extends CarParts{}
class Chassis extends CarParts{}
class Motor extends CarParts{}
class Body extends CarParts{}

class CarPartsResolver extends TypeIdResolverBase {

    private JavaType superType;

    @Override
    public void init(JavaType javaType) {
        this.superType = javaType;
    }

    @Override
    public String idFromValue(Object o) {
        return idFromValueAndType(o, o.getClass());
    }

    @Override
    public String idFromValueAndType(Object o, Class<?> aClass) {
        return aClass.getSimpleName();
    }

    @Override
    public JavaType typeFromId(DatabindContext context, String id) throws IOException {
        Class<?> subType = null;
        switch (id) {
            case "Engine": subType = Engine.class; break;
            case "Chassis": subType = Chassis.class; break;
            case "Motor": subType = Motor.class; break;
            case "Body": subType = Body.class; break;
        }
        return context.constructSpecializedType(superType, subType);
    }

    @Override
    public JsonTypeInfo.Id getMechanism() {
        return JsonTypeInfo.Id.CUSTOM;
    }
}

Stacktrace

Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Missing type id when trying to resolve subtype of [simple type, class com.temp.CarParts]: missing type id property 'type' (for POJO property 'Object')
 at [Source: (StringReader); line: 3, column: 40] (through reference chain: com.temp.Auto["Object"]->java.util.ArrayList[0]->com.temp.Engine["Object"]->java.util.ArrayList[0])
	at com.fasterxml.jackson.databind.exc.InvalidTypeIdException.from(InvalidTypeIdException.java:43)
	at com.fasterxml.jackson.databind.DeserializationContext.missingTypeIdException(DeserializationContext.java:1794)
	at com.fasterxml.jackson.databind.DeserializationContext.handleMissingTypeId(DeserializationContext.java:1323)
	at com.fasterxml.jackson.databind.jsontype.impl.TypeDeserializerBase._handleMissingTypeId(TypeDeserializerBase.java:303)
	at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer._deserializeTypedUsingDefaultImpl(AsPropertyTypeDeserializer.java:166)
	at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromObject(AsPropertyTypeDeserializer.java:107)
	at com.fasterxml.jackson.databind.deser.AbstractDeserializer.deserializeWithType(AbstractDeserializer.java:254)
	at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:293)
	at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:250)
	at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:27)
	at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:138)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:293)

PS: Above code is able to parse following XMLs

<Auto>
    <Object type="Engine">
        <Object type="Chassis"></Object>
        <Object type="Motor"></Object>
    </Object>
    <Object type="Body"></Object>
</Auto>
<Auto>
    <Object uid="1" type="Engine"></Object>
    <Object uid="4" type="Body"></Object>
</Auto>

but fails on

<Auto>
    <Object uid="1" type="Engine">
        <Object uid="2" type="Chassis"></Object>
        <Object uid="3" type="Motor"></Object>
    </Object>
    <Object uid="4" type="Body"></Object>
</Auto>

Issue Analytics

  • State:open
  • Created 3 years ago
  • Comments:7 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
cowtowncodercommented, Oct 1, 2020

Thank you for reporting this issue. I hope to look into this in near future.

0reactions
cowtowncodercommented, Jul 8, 2021

Looks like part of this is buffering: switching order of type and uid for first 2 elements actually makes test pass. This is probably since buffering with TokenBuffer will by-pass all XML specific logic of FromXmlParser – a known potential problem, but in this case actual problem it appears.

Will give up for now, hope to address eventually.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to deserealize multiple nested elements in Jackson?
How can I deserealize the entire XML file? My code looks like this: MyClass.java private static void jacksonXmlFileToObject() throws IOException ...
Read more >
DeserializationContext - java.lang.Object - Adobe Developer
Method called for secondary property deserializers (ones NOT directly created to deal with an annotatable POJO property, but instead created as a component ......
Read more >
Red Hat JBoss Enterprise Application Platform 7.1.0.Beta1
Offlined method called to handle "native" Object Id that has been read and known to be associated with given deserialized POJO.
Read more >
ObjectMapper (jackson-databind 2.9.0 API) - FasterXML
ObjectMapper provides functionality for reading and writing JSON, either to and from basic POJOs (Plain Old Java Objects), or to and from a...
Read more >
Solving the XML Problem with Jackson - DZone
Reading from a java.io.File. Jackson Annotations for Serialization. The Jackson XML module supports the full range of annotations that Jackson ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found