我发现在Java 7上处理Jaxb与Java 8之间存在另一个区别。我已将问题简化为简化示例,并且代码应作为单个类运行。 (更改了类别,使其与非工作相关等)当Unmarshaller调用List的setter时: 我的问题实际上是
的变体在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时开始表现出微妙(但很重要)的差异,但没有任何明显的例外。
答案 0 :(得分:1)
我们遇到了同样的问题,正如this blog post所述。
- 编码JaxB时,编码List访问器的推荐做法是否完全省略Setter? (因为它似乎通过Getter处理List)
- 是否有推荐的替代方法?
醇>
重点不是“省略Setter”而是为了向setter添加更多功能。塞特只是二传手,仅此而已。添加更多逻辑违反了setter的“单一责任规则”,并且该函数的名称与实际执行的内容不同,可能会出现更多错误。
当推荐的方式出现时,没有涵盖所有情况的标准答案。考虑到没有构造函数init(这对JAXB来说有点难度),并且我们在setter之后需要更多的逻辑,我们有两个方向你可以采取:
XmlAdapter
自定义构造以添加逻辑:adapter examples;