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

JAXB ignores overridden getter giving XXX is an interface, and JAXB can't handle interfaces #1811

Open
PavelTurk opened this issue Aug 15, 2024 · 0 comments

Comments

@PavelTurk
Copy link

This is my code:

import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Marshaller;
import jakarta.xml.bind.Unmarshaller;
import jakarta.xml.bind.annotation.XmlAttribute;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.adapters.XmlAdapter;
import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

import java.io.StringReader;
import java.io.StringWriter;
import java.util.HashSet;
import java.util.Set;


public class Test {

    public static interface Teacher {
        String getName();
    }

    public static class ConcreteTeacher implements Teacher {
        private String name;

        public ConcreteTeacher() {

        }

        public ConcreteTeacher(String name) {
            this.name = name;
        }

        @Override
        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return name;
        }
    }

    public static class GroupParent {

        private Set<Teacher> teachers;

        public Set<Teacher> getTeachers() {
            return teachers;
        }

        public void setTeachers(Set<Teacher> teachers) {
            this.teachers = teachers;
        }
    }

    @XmlRootElement(name = "group")
    public static class Group extends GroupParent {

        @Override
        @XmlElement(name = "teachers")
        @XmlJavaTypeAdapter(TeacherAdapter.class)
        public Set<Teacher> getTeachers() {
            return super.getTeachers();
        }
    }

    public static class TeacherAdapter extends XmlAdapter<TeacherAdapter.AdaptedTeachers, Set<Teacher>> {

        public static class AdaptedTeachers {
            @XmlElement(name = "teacher")
            public Set<AdaptedTeacher> teacherList = new HashSet<>();
        }

        public static class AdaptedTeacher {
            @XmlAttribute(name = "name")
            public String name;
        }

        @Override
        public Set<Teacher> unmarshal(AdaptedTeachers adaptedTeachers) throws Exception {
            Set<Teacher> teachers = new HashSet<>();
            for (AdaptedTeacher adaptedTeacher : adaptedTeachers.teacherList) {
                teachers.add(new ConcreteTeacher(adaptedTeacher.name));
            }
            return teachers;
        }

        @Override
        public AdaptedTeachers marshal(Set<Teacher> teachers) throws Exception {
            AdaptedTeachers adaptedTeachers = new AdaptedTeachers();
            for (Teacher teacher : teachers) {
                AdaptedTeacher adaptedTeacher = new AdaptedTeacher();
                adaptedTeacher.name = teacher.getName();
                adaptedTeachers.teacherList.add(adaptedTeacher);
            }
            return adaptedTeachers;
        }
    }

    private static final String XML_STRING = """
        <group>
            <teachers>
                <teacher name="Alice"/>
                <teacher name="Bob"/>
            </teachers>
        </group>
    """;

    public static void main(String[] args) {
        try {
            JAXBContext context = JAXBContext.newInstance(Group.class);

            Group group = new Group();
            Set<Teacher> teachers = new HashSet<>();
            teachers.add(new ConcreteTeacher("Alice"));
            teachers.add(new ConcreteTeacher("Bob"));
            group.setTeachers(teachers);

            Marshaller marshaller = context.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
            StringWriter writer = new StringWriter();
            marshaller.marshal(group, writer);
            String xml = writer.toString();
            System.out.println("Serialized XML:");
            System.out.println(xml);

            Unmarshaller unmarshaller = context.createUnmarshaller();
            StringReader reader = new StringReader(XML_STRING);
            Group deserializedGroup = (Group) unmarshaller.unmarshal(reader);
            System.out.println("Deserialized Group:");
            for (Teacher teacher : deserializedGroup.getTeachers()) {
                System.out.println(teacher.getName());
            }
        } catch (JAXBException e) {
            e.printStackTrace();
        }
    }
}

If you run it, it will give:

org.glassfish.jaxb.runtime.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
com.foo.mavenproject19.Test$Teacher is an interface, and JAXB can't handle interfaces.
	this problem is related to the following location:
		at com.foo.mavenproject19.Test$Teacher
		at public java.util.Set com.foo.mavenproject19.Test$GroupParent.getTeachers()
		at com.foo.mavenproject19.Test$GroupParent
		at com.foo.mavenproject19.Test$Group

But, if you update it to

    @XmlRootElement(name = "group")
    public static class Group { 

        private Set<Teacher> teachers;

        @XmlElement(name = "teachers")
        @XmlJavaTypeAdapter(TeacherAdapter.class)
        public Set<Teacher> getTeachers() {
            return teachers;
        }

        public void setTeachers(Set<Teacher> teachers) {
            this.teachers = teachers;
        }
    }

Then everything works fine.

The problem of this issue is important in case when you have a class from one project that doesn't use XML and you need to write/read it to/from XML file in another project, so you use inheritance.

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

1 participant