JAXB Java 7与Java 8的区别

时间:2016-04-01 16:15:43

标签: jaxb

我发现在Java 7上处理Jaxb与Java 8之间存在另一个区别。我已将问题简化为简化示例,并且代码应作为单个类运行。 (更改了类别,使其与非工作相关等)当Unmarshaller调用List的setter时: 我的问题实际上是

的变体
  1. 编码列表访问器的推荐做法是省略 在编写JaxB时完全是Setter? (因为它似乎确实处理了 通过Getter列出)
  2. 是否有推荐的替代方法?
  3. 在Java 7中运行时,将使用List中的数据调用setter。 当在Java 8中运行时,将仅使用空的List对象调用setter,该对象显然在稍后的解组过程中被填充。 我遇到的不同之处在于我不能让setter对List执行任何处理,而是只有在整个对象被解组后才调用的进程。或者总结一下,"不要在setter中做任何处理"。 示例如下:(三个类) - 在Java 7下,返回的结果是第一个"专辑"列表中的标题可以在setter中找到。在Java 8下,返回null。 代码应该作为单个类运行,没有依赖项。 如果在Java 7" First Album"中运行显示的标题是" Abbey Road"。 如果在Java 8" First Album"中运行title为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;
        }
    }
    

    出现这个问题是因为我们的代码在切换到Java 8时开始表现出微妙(但很重要)的差异,但没有任何明显的例外。

1 个答案:

答案 0 :(得分:1)

我们遇到了同样的问题,正如this blog post所述。

  
      
  1. 编码JaxB时,编码List访问器的推荐做法是否完全省略Setter? (因为它似乎通过Getter处理List)
  2.   
  3. 是否有推荐的替代方法?
  4.   

重点不是“省略Setter”而是为了向setter添加更多功能。塞特只是二传手,仅此而已。添加更多逻辑违反了setter的“单一责任规则”,并且该函数的名称与实际执行的内容不同,可能会出现更多错误。

当推荐的方式出现时,没有涵盖所有情况的标准答案。考虑到没有构造函数init(这对JAXB来说有点难度),并且我们在setter之后需要更多的逻辑,我们有两个方向你可以采取:

  • 使用XmlAdapter自定义构造以添加逻辑:adapter examples;
  • 不在此类中添加任何逻辑,创建另一个类来处理来自xml的数据 - (这是首选,因为这个类只是一些不应该有逻辑的DTO)