3

How can we marshal objects into XML files using JAXB when we use interfaces for our classes? I have the following simple classes:

public interface IBook {

    public abstract String getName();

    public abstract void setName(String name);

}
@XmlRootElement
public class Book implements IBook {

    private String name;

    @Override
    @XmlElement(name ="BookTitle")
    public String getName() {
        return name;
    }

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


@XmlRootElement
public class BookStore {

    @XmlElement(name ="BookStoreName")
    public String name;

    @XmlElementWrapper(name ="bookList")
    @XmlAnyElement
    public HashSet<IBook> books= new HashSet<IBook>();

    }

and when I try to marshal an object from BookStore into an XML file, I get the following error:

[com.sun.istack.internal.SAXException2: Weder class de.uni_paderborn.books.Book noch eine der zugehörigen Superklassen ist diesem Kontext bekannt.

javax.xml.bind.JAXBException: Weder class de.uni_paderborn.books.Book noch eine der zugehörigen Superklassen ist diesem Kontext bekannt.]

Sorry for the German error message, but my OS is German. This means that neither the class Book nor one of its superclasses is known in this context! Why do I get such an error?

3
  • You may find the following useful: blog.bdoughan.com/2011/05/…. Also, I'm curious why you are using @XmlAnyElement on the books field. Commented Dec 5, 2014 at 15:42
  • Because without it I get another error that tells I am trying to marshal an interface, since the elements in books HashSet are from IBook, and not from Book. Thanks! Commented Dec 5, 2014 at 15:53
  • I have added an answer that should help: stackoverflow.com/a/27319803/383861 Commented Dec 5, 2014 at 15:55

4 Answers 4

3

The problem is that you are missing @XmlSeeAlso in your BookStore class. Add it to your BookStore class like this

@XmlRootElement
@XmlSeeAlso({Book.class})
public class BookStore {

    @XmlElement(name = "BookStoreName")
    public String name;

    @XmlElementWrapper(name = "bookList")
    @XmlAnyElement
    public HashSet<IBook> books = new HashSet<IBook>();


    public static void main(String[] args) throws JAXBException {
        BookStore bookStore = new BookStore();
        bookStore.name = "FooBookStore";
        Book e = new Book();
        e.setName("Java");
        bookStore.books.add(e);

        /**
         * Create JAXB Context from the classes to be serialized
         */
        JAXBContext context = JAXBContext.newInstance(BookStore.class);
        Marshaller m = context.createMarshaller();
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        m.marshal(bookStore, System.out);
    }
}

Outputs

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<bookStore>
    <BookStoreName>FooBookStore</BookStoreName>
    <bookList>
        <book>
            <BookTitle>Java</BookTitle>
        </book>
    </bookList>
</bookStore>
Sign up to request clarification or add additional context in comments.

2 Comments

should I add this @XmlSeeAlsofor each class type that I might use in the list of books? Thanks!
Yes , if they are different impls
1

Generally to map a field/property that is an interface type you use the type setting on the @XmlElement annotation.

@XmlElementWrapper(name ="bookList")
@XmlElement(type=Book.class, name="book")
public HashSet<IBook> books= new HashSet<IBook>();

4 Comments

OK, thanks! it is similar to the previous answer, but again, should I mention each and every class that may go into my HashSet<IBook> books?
@Anas You have different impls that can go in?
Yes, they can be from different impls
actually, I just found out that this solution is better than the other since in the unmarshalling process I get the objects from the exact required classes. But the question remains, what about the situation in which I have multiple possible implementations of my interfaces?
0

I had another problem for the same exception. I had 2 Different BookStore classes where only packages differ: hello.number.one.BookStore hello.number.two.BookStore

My error was I was filling XML set with package ..one.. But included the BookStore class with package ..two.. because eclipse included it like that for me (automatically), and so did not notice the wrong BookStore class. JAXBContext context = JAXBContext.newInstance(BookStore.class);

it is simple but long searching indeed...hope it helps somewhere

Comments

0

I had exactly the same problem while working with spring resp. adding a Jaxb2Marshaller bean. i had the same error message because of not setting the

marshaller.setPackagesToScan(...)

properly with the right package names of the generated files, wich resulted in the same exception.

@Bean(name = "someMarshaller"
Jaxb2Marshaller someMarshaller() {
    final Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
    marshaller.setPackagesToScan("my.package.one", "my.package.two");
    return marshaller;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.