【发布时间】:2016-02-12 20:14:42
【问题描述】:
我有一个相当标准的用例,它给我带来了非标准问题。
我在服务器上运行了一个 Java Web 应用程序(使用 Jersey 和 Hibernate)。它有一个从浏览器内 Javascript 调用的 AJAX api。
此服务向 ajax 公开:
import list.nice.bll.UserBLL;
import list.nice.dal.dto.Token;
import list.nice.dal.dto.User;
import org.glassfish.jersey.media.multipart.FormDataBodyPart;
import org.glassfish.jersey.media.multipart.FormDataMultiPart;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.*;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
import java.io.*;
import java.net.URISyntaxException;
import java.security.GeneralSecurityException;
@Path("/users")
public class UserInfoService {
@POST
@Path("/getUser")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response getUserFromLogin(JAXBElement<User> user){
User rUser = user.getValue();
rUser = UserInfoService.getActiveUser(rUser.getUserID());
return Response.status(Response.Status.OK).header("Access-Control-Allow-Origin", "*").entity(UserInfoService.getActiveUser(rUser.getUserID())).build();
}
}
我有一个对应于用户表的用户类。每个用户都有朋友,但我不需要我加载的每个用户的朋友(无需一次获取整个对象图)。
User.java 看起来像这样:
@Entity
@Table(name="users")
public class User {
@Id
@GeneratedValue(generator = "increment")
@GenericGenerator(name="increment", strategy = "increment")
private int userID;
private String name;
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinTable(name = "friendships", joinColumns = @JoinColumn(name="requesteruserID"), inverseJoinColumns = @JoinColumn(name="requesteduserID"))
@WhereJoinTable(clause = "accepted = 'TRUE'")
private Set<User> friends = new HashSet<User>();
public User(){}
public User(int userID, String name) {
this.userID = userID;
this.name = name;
}
public int getUserID() {
return userID;
}
public void setUserID(int userID) {
this.userID = userID;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<User> getFriends() {
return friends;
}
public void setFriends(Set<User> friends) {
this.friends = friends;
}
当我检索活动用户时,我想立即检索他们的所有朋友,而不是朋友的朋友(以及更多)。所以我的getActiveUser() 函数看起来像这样:
protected static User getActiveUser(int userID) {
EntityManager entityManager = HibernateUtil.getEntityManagerFactory().createEntityManager();
User user = (User) entityManager.createQuery("from User where userID = :userID").setParameter("userID", userID).getSingleResult();
user.getFriends();
//I have also tried Hibernate.initialize(user.getFriends())
entityManager.close();
return user;
}
对这个函数的 Ajax 调用最终得到一个 500 内部服务器错误,但服务器没有给我太多数据(它继续运行,好像什么都没发生一样)。调试控制台中打印的内容如下:
Feb 12, 2016 1:49:13 PM org.hibernate.engine.jdbc.env.internal.LobCreatorBuilderImpl useContextualLobCreation
INFO: HHH000424: Disabling contextual LOB creation as createClob() method threw error : java.lang.reflect.InvocationTargetException
Feb 12, 2016 1:49:13 PM org.hibernate.type.BasicTypeRegistry register
INFO: HHH000270: Type registration [java.util.UUID] overrides previous : org.hibernate.type.UUIDBinaryType@6505e696
Feb 12, 2016 1:49:13 PM org.hibernate.jpa.internal.util.LogHelper logPersistenceUnitInformation
INFO: HHH000204: Processing PersistenceUnitInfo [
name: myapp.mypackage
...]
Feb 12, 2016 1:49:14 PM org.hibernate.engine.jdbc.env.internal.LobCreatorBuilderImpl useContextualLobCreation
INFO: HHH000424: Disabling contextual LOB creation as createClob() method threw error : java.lang.reflect.InvocationTargetException
Feb 12, 2016 1:49:14 PM org.hibernate.type.BasicTypeRegistry register
INFO: HHH000270: Type registration [java.util.UUID] overrides previous : org.hibernate.type.UUIDBinaryType@6505e696
Feb 12, 2016 1:49:14 PM org.hibernate.hql.internal.QueryTranslatorFactoryInitiator initiateService
INFO: HHH000397: Using ASTQueryTranslatorFactory
但是,我认为这不是有用的信息,因为如果我将加载切换到 EAGER,它会在控制台中提供相同的消息,但工作正常。
除此之外,我基本上完全迷失了,但为了完整起见,这是我尝试过的一件事也没有奏效:
我决定试一试自定义 XMLAdapter,因为我在调试时注意到 friends 是 PersistentSet,我认为可能 Jersey 处理得不好。
所以我像这样更改了 User 类:
@XmlJavaTypeAdapter(FriendAdapter.class)
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinTable(name = "friendships", joinColumns = @JoinColumn(name="requesteruserID"), inverseJoinColumns = @JoinColumn(name="requesteduserID"))
@WhereJoinTable(clause = "accepted = 'TRUE'")
private Set<User> friends = new HashSet<User>();
FriendAdapter 看起来像这样:
import org.hibernate.collection.internal.PersistentSet;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import java.util.*;
public class FriendAdapter extends XmlAdapter<List<User>, Set> {
@Override
public Set unmarshal(List<Friend> v) throws Exception {
return new HashSet<Friend>(v);
}
@Override
public List<Friend> marshal(Set v) throws Exception {
PersistentSet p = (PersistentSet) v;
if(p.empty()) {
return null;
}
return new ArrayList<Friend>(Arrays.asList((Friend[])v.toArray(new Friend[0])));
}
}
这给了我一个非常奇怪的结果:在序列化之后,进行 ajax 调用的 Web 浏览器将获得(而不是正常的对象数组)一个字符串,其内容为 "myapp.mypackage.User@3c81a180 myapp.mypackage.User@28d2a9cf myapp.mypackage.User@19c74a79"
我应该怎么做才能克服这个问题?急切加载可以解决所有问题,但我不想加载 Friends-of-friends-of-friends。
【问题讨论】:
-
你看到你的服务器日志了吗?另外,您到底在哪里尝试序列化您的 java 对象?我的意思是说你的对象序列化的目的是什么?
-
我的大部分登录都没有,因为我正在调试并且无论如何它都会打印到控制台。我的 Tomcat 日志没有任何有趣的内容,只有 ajax 调用的时间戳。
-
为了测试序列化过程的工作,您可以做的是尝试在getActiveUsers()方法中显式序列化对象并测试序列化是否适用于对象而没有错误。你也没有透露你打算如何使用对象的序列化。
-
“你也没有透露你打算如何使用对象的序列化。”我不确定你在这里的意思。我将其序列化为 JSON 以发送回发出 AJAX 调用的浏览器 Javascript。为了清楚起见,我将用更多代码编辑我的帖子。
标签: java hibernate jpa serialization jersey