我有一些JPA代码(以Hibernate作为提供者)抛出可怕的ClassCastException。但是,它似乎只发生在某些计算机上,而不是具有完全相同的代码库,配置,数据库架构和数据的其他计算机上。有没有人遇到过这个?有办法解决吗?我相当肯定这不是我的代码中的错误,因为它在某些环境中工作(在较新的Macbook Pro上的开发机器上)但在其他环境中没有(Mac Mini和Amazon Linux AMI)。
作为参考,当尝试使用摘要式身份验证通过Spring Security对用户进行身份验证时,会显示此信息。 Spring配置为通过调用实现UserDetailsService接口的bean来检索用户列表:
@Component("httpDigestUserDetailsService")
public class HttpDigestUserDetailsService implements UserDetailsService {
private static final Logger log = LoggerFactory.getLogger(HttpDigestUserDetailsService.class);
@Autowired
UserService userService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
List<User> users = userService.findBy("username", username);
User user = users.get(0);
return new HttpDigestUserDetails(user);
}
调用userService.findBy()
时发生错误。 UserService
由UserServiceImpl
实施,如下所示:
@Transactional(propagation = Propagation.REQUIRED)
public class UserServiceImpl extends AbstractService<User> implements UserService {
private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
@Override
public Class getPersistentObjectClass() {
return User.class;
}
public void signUp(User user) {
user.addUserRole(UserRole.ROLE_USER);
save(user);
}
}
真正的findBy
方法在AbstractRestService
中实现:
@Transactional(propagation = Propagation.REQUIRED)
public abstract class AbstractService<T extends PO> implements EntityService<T> {
public List<T> findBy(String ... fields) {
Map<String, Object> map = new HashMap<String, Object>();
for (int i=0; i<fields.length - 1; i+=2) {
map.put(fields[i], fields[i+1]);
}
return findBy(map);
}
public List<T> findBy(Map<String, Object> fields) {
String queryString = String.format("SELECT o FROM %s o", getPersistentObjectClass().getName());
StringBuilder sb = new StringBuilder();
Set<String> fieldsSet = fields.keySet();
boolean first = true;
for (String fieldName : fieldsSet) {
if (first) { sb.append(" WHERE "); first = false; } else sb.append(" AND ");
sb.append(String.format("o.%s = :%s", fieldName, fieldName));
}
queryString = queryString + sb.toString();
TypedQuery<T> q = getEntityManager().createQuery(queryString, getPersistentObjectClass());
for (String fieldName : fieldsSet) {
q.setParameter(fieldName, fields.get(fieldName));
}
List<T> results = q.getResultList();
return results;
}
}
User
域对象的注释如下(省略只是简单属性的getter / setter:
@Entity
@Table(name = "users")
public class User extends PO {
private Patient patient;
private Provider provider;
private Set<UserRole> userRoles;
@OneToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "patient_id", nullable = true)
public Patient getPatient() {
return Patient;
}
public void setPatient(Patient patient) {
this.patient = patient;
}
@OneToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "provider_id", nullable = true)
public Provider getProvider() {
return provider;
}
public void setProvider() {
this.provider = provider;
}
@OneToMany(mappedBy = "user", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
public Set<UserRole> getUserRoles() {
return userRoles;
}
public void setUserRoles(Set<UserRole> userRoles) {
this.userRoles = userRoles;
}
}
最后,所有域对象都扩展的PO
基础对象:
@MappedSuperclass
public class PO implements Serializable {
private Long id;
@Id
@GeneratedValue
@Column(name = "id")
public Long getId() {
return id;
}
}
Patient
和Provider
也会扩展PO,并将逆映射返回给User。我可以添加该代码,如果它有用的话。
最后,这是我收到的异常和堆栈跟踪:
HTTP Status 500 - org.hibernate.PropertyAccessException: IllegalArgumentException occurred calling getter of PO.id; nested exception is javax.persistence.PersistenceException: org.hibernate.PropertyAccessException: IllegalArgumentException occurred calling getter of PO.id
java.lang.IllegalArgumentException: java.lang.ClassCastException@7e46a468
sun.reflect.GeneratedMethodAccessor57.invoke(Unknown Source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:606)
org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:164)
org.hibernate.tuple.entity.AbstractEntityTuplizer.getIdentifier(AbstractEntityTuplizer.java:341)
org.hibernate.persister.entity.AbstractEntityPersister.getIdentifier(AbstractEntityPersister.java:4491)
org.hibernate.persister.entity.AbstractEntityPersister.isTransient(AbstractEntityPersister.java:4213)
org.hibernate.engine.internal.ForeignKeys.isTransient(ForeignKeys.java:209)
org.hibernate.engine.spi.CascadingAction$8.noCascade(CascadingAction.java:375)
org.hibernate.engine.internal.Cascade.cascade(Cascade.java:176)
org.hibernate.event.internal.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:160)
org.hibernate.event.internal.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:151)
org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:88)
org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1213)
org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:402)
org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:75)
org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:512)
org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:394)
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622)
com.luminatehealth.service.UserServiceImpl$$EnhancerByCGLIB$$2a6af235.findBy(<generated>)
com.luminatehealth.rest.security.HttpDigestUserDetailsService.loadUserByUsername(HttpDigestUserDetailsService.java:33)
org.springframework.security.web.authentication.www.DigestAuthenticationFilter.doFilter(DigestAuthenticationFilter.java:144)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:150)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
我已经阅读过关于在加载从共享超类扩展的域对象时如何创建代理对象的Hibernate问题,但是我看到的大多数建议都应该确保您将注释放在属性上不是字段(我们已经在做),或者使用急切加载来避免代理被创建(我们所有的关联都使用了预先加载)。我也很困惑为什么代理被创建,因为我认为只有当你需要延迟加载关联时才会发生。我假设在这种情况下它与事务管理有关。
我一直在撞墙挡住了两天,现在进展不大,所以我很感激任何指针。