I've found another difference between handling Jaxb on Java 7 versus Java 8. I've reduced the issue to a simplified example, and the code should run as a single class. (changed the categories so it's non-work-related etc) When the setter for a List is called by the Unmarshaller: My Question is really a variation of
- Is the recommended practice for coding List accessors to omit the Setter altogether when coding JaxB ? ( since it seems to do handle the List via the Getter )
- Are there recommended alternative approaches?
When run in Java 7 the setter will be called with data in the List. When run in Java 8 the setter will be called only with an empty List object which apparently gets populated later in the unmarshalling process. The difference I experience is that I must not have the setter do any processing on the List, but rather have a process that is invoked only after the overall object is unmarshalled. Or to sum it up, "don't do any processing in the setter". Example is below: (Three classes) - Under Java 7 the result returned is the first "album" title on the list as found in the setter. Under Java 8 a null is returned. The code should run as a single class with no dependencies. If run in Java 7 "First Album" title displayed is "Abbey Road". If run in Java 8 "First Album" title is null
import java.io.ByteArrayInputStream; import java.io.InputStream; import java.util.List; import javax.xml.bind.JAXBContext; import javax.xml.bind.Unmarshaller; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType; public class MainJaxbCase { public static void main( String[] args ) { new MainJaxbCase().testIt(); } private void testIt() { try { AlbumLib myLib = (AlbumLib) loadJaxbDocFromString( inXmlStr, AlbumLib.class ); System.out.println("category:"+ myLib.getCateg()); List<AlbumItm> albumList = myLib.getAlbumList(); System.out.println("AlbumList size is " + albumList.size()); System.out.println("The first album is titled:" + myLib.getFirstAlbumTitle() + "- shows \"null\" if using Java 8, \"Abbey Road\" if using Java 7" ); } catch ( Exception e ) { System.out.println( e.getClass().getSimpleName() + ", msg:" + e.getMessage() ); e.printStackTrace(); } } private final String inXmlStr = "<my_lib categ='albums'>" + " <album title='Abbey Road'/> " + " <album title='Revolver'/>" + " <album title='Sgt.Pepper'/>" + "</my_lib>"; private Object loadJaxbDocFromString ( String inStr, Class<?> clazz ) throws Exception { Object result = null; try { InputStream is = new ByteArrayInputStream( inStr.getBytes() ); result = unmarshal( is, clazz ); } catch ( Exception e ) { String msg = this.getClass().getSimpleName() + ".loadJaxbDocFromResource() caught " + e.getClass().getSimpleName() + " msg:" + e.getMessage(); throw new Exception(msg); } return result; } private Object unmarshal( InputStream prmIs, Class<?> clazz ) throws Exception{ Object obj = null; try { JAXBContext jaxbContext = JAXBContext.newInstance( clazz ); Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); obj = jaxbUnmarshaller.unmarshal( prmIs ); } catch ( Exception e ) { String msg = this.getClass().getSimpleName() + " caught " + e.getClass().getSimpleName() + ", msg:" + e.getMessage(); msg += " Trying to Unmarshall class " + clazz.getName(); System.err.println(msg); e.printStackTrace(); throw new Exception(msg); } return obj; } } @XmlRootElement ( name= "my_lib") class AlbumLib { private String categ; private List<AlbumItm> albumList; private String firstAlbumTitle; @XmlAttribute ( name="categ") public String getCateg() { return this.categ; } public void setCateg( String val ) { this.categ=val; } @XmlElement ( name="album") public List<AlbumItm> getAlbumList() { return this.albumList; } public void setAlbumList( List<AlbumItm> newList ) { if ( newList != null && newList.size() > 0 ) { firstAlbumTitle = newList.get(0).getTitle(); } this.albumList = newList; } public String getFirstAlbumTitle() { return this.firstAlbumTitle; } } @XmlType(name = "album") class AlbumItm { private String title; @XmlAttribute ( name="title" ) public String getTitle() { return this.title; } public void setTitle(String val ) { this.title = val; } }
This question arose because we had code that started behaving with subtle (but important) differences when it was switched to Java 8, but without any obvious exceptions.