2011-05-13 52 views
5

JPA规范中是否有描述有效的@Embeddable类的内容?我看过但找不到任何东西。@Embeddable类可以是私人的吗?

我使用EclipseLink(2.3.0-M7-完整构建字符串2.3.0.v20110429-r9282)与Hibernate(3.6.4.Final)和Spring(3.0.5),并已建立我的应用程序的记录在EclipseLink/Examples/MOXy/Spring/JAXBAnnotations。目前所有的东西都可以工作并且持续数月。我正在添加一个@Embeddable类,并开始获得NPE。

这里是一些示例代码,我希望有人可以用它来重现这一点,如果它是EclipseLink的错误,因为我删除EclipseLink库和配置(并恢复到Hibernate的实现),那么我不再获得NPE。

测试类Broken.java

package x.y.z.model; 

import javax.persistence.*; 
import javax.xml.bind.annotation.*; 
import java.io.Serializable; 

@Entity 
public class Broken { 
    @EmbeddedId 
    private Pk pk = new Pk(); 

    @Embeddable 
    private static class Pk implements Serializable { 
     @ManyToOne 
     private String foo; 

     public String getFoo() { 
      return this.foo; 
     } 
     public void setFoo(String foo) { 
      this.foo = foo; 
     } 
    } 
} 

Spring bean配置我的是:

<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller"> 
    <property name="contextPath" value="x.y.z.model"/> 
</bean> 
<bean id="xmlHelper" class="x.y.xml.XMLHelper"> 
    <property name="marshaller" ref="jaxbMarshaller"/> 
</bean> 

(见上面链接XMLHelper类)

最后我想补充以下到jaxb.in​​dex

Broken 

当启动Spring应用程序,我得到以下异常:

ERROR org.springframework.test.context.TestContextManager 324 - Caught exception while allowing TestExecutionListener [org.springframewor[email protected]9b601d] to prepare test instance [[email protected]] 
java.lang.IllegalStateException: Failed to load ApplicationContext 
    at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:308) 
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:109) 
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75) 
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:321) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:220) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:301) 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:303) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184) 
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) 
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) 
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180) 
    at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:35) 
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:115) 
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:97) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at org.apache.maven.surefire.booter.ProviderFactory$ClassLoaderProxy.invoke(ProviderFactory.java:103) 
    at $Proxy0.invoke(Unknown Source) 
    at org.apache.maven.surefire.booter.SurefireStarter.invokeProvider(SurefireStarter.java:150) 
    at org.apache.maven.surefire.booter.SurefireStarter.runSuitesInProcess(SurefireStarter.java:91) 
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:69) 
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jaxbMarshaller' defined in class path resource [applicationContext.xml]: Invocation of init method failed; nested exception is org.springframework.oxm.UncategorizedMappingException: Unknown JAXB exception; nested exception is 
javax.xml.bind.JAXBException 
- with linked exception: 
[java.lang.NullPointerException] 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1420) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456) 
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291) 
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190) 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:580) 
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:895) 
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425) 
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:84) 
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:1) 
    at org.springframework.test.context.TestContext.loadApplicationContext(TestContext.java:280) 
    at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:304) 
    ... 31 more 
Caused by: org.springframework.oxm.UncategorizedMappingException: Unknown JAXB exception; nested exception is javax.xml.bind.JAXBException 
- with linked exception: 
[java.lang.NullPointerException] 
    at org.springframework.oxm.jaxb.Jaxb2Marshaller.convertJaxbException(Jaxb2Marshaller.java:668) 
    at org.springframework.oxm.jaxb.Jaxb2Marshaller.getJaxbContext(Jaxb2Marshaller.java:335) 
    at org.springframework.oxm.jaxb.Jaxb2Marshaller.afterPropertiesSet(Jaxb2Marshaller.java:317) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1477) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1417) 
    ... 44 more 
Caused by: javax.xml.bind.JAXBException 
- with linked exception: 
[java.lang.NullPointerException] 
    at org.eclipse.persistence.jaxb.JAXBContext$ContextPathInput.createContextState(JAXBContext.java:661) 
    at org.eclipse.persistence.jaxb.JAXBContext$ContextPathInput.createContextState(JAXBContext.java:621) 
    at org.eclipse.persistence.jaxb.JAXBContext.<init>(JAXBContext.java:134) 
    at org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(JAXBContextFactory.java:108) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:128) 
    at javax.xml.bind.ContextFinder.find(ContextFinder.java:249) 
    at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:372) 
    at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:337) 
    at org.springframework.oxm.jaxb.Jaxb2Marshaller.createJaxbContextFromContextPath(Jaxb2Marshaller.java:355) 
    at org.springframework.oxm.jaxb.Jaxb2Marshaller.getJaxbContext(Jaxb2Marshaller.java:328) 
    ... 47 more 
Caused by: java.lang.NullPointerException 
    at org.eclipse.persistence.jaxb.javamodel.Helper.isBuiltInJavaType(Helper.java:261) 
    at org.eclipse.persistence.jaxb.compiler.AnnotationsProcessor.shouldGenerateTypeInfo(AnnotationsProcessor.java:1526) 
    at org.eclipse.persistence.jaxb.compiler.AnnotationsProcessor.processClass(AnnotationsProcessor.java:1029) 
    at org.eclipse.persistence.jaxb.compiler.AnnotationsProcessor.processAdditionalClasses(AnnotationsProcessor.java:994) 
    at org.eclipse.persistence.jaxb.compiler.AnnotationsProcessor.postBuildTypeInfo(AnnotationsProcessor.java:576) 
    at org.eclipse.persistence.jaxb.compiler.AnnotationsProcessor.processClassesAndProperties(AnnotationsProcessor.java:230) 
    at org.eclipse.persistence.jaxb.compiler.Generator.<init>(Generator.java:104) 
    at org.eclipse.persistence.jaxb.JAXBContext$ContextPathInput.createContextState(JAXBContext.java:658) 
    ... 60 more 

如果我改变@Embeddable类从私人公共(和使用的EclipseLink),该NPE不再发生。所以我有一个解决方案,但想知道为什么。

+0

确实很不错。 +1 – 2011-05-13 11:06:55

回答

3

JPA 2.0 Specification指出可嵌入类必须遵守为实体描述的相同要求。这些要求在说明书的第2.1节的规定,他们指出:

  • 实体类必须有一个无参数的构造函数。它也可能有其他的构造函数。无参数构造函数必须是公共的或受保护的。
  • 实体类必须是顶级类。枚举或接口一定不能是 指定为实体。
  • 实体类一定不能是final。实体类的方法或持久化实例变量可能是最终的。

因此,我认为,是什么影响了你可能是嵌入类不是顶层类,加上事实上,它是私有的。

您可能会喜欢尝试。即使这不是原因,您可能会考虑遵循标准的建议,否则,您无法保证您的代码符合该标准。

+0

+1谢谢!我认为你可能会有_top-level class_要求的答案,因为顶级类不能是_private_。我将尝试使用一些不同的JPA 2.0供应商,并了解他们如何处理此问题。我绝对同意遵守标准。我不确定为什么我首先宣布班级_private_! – andyb 2011-05-13 19:41:42

1

这可能更依赖于底层impl如何加载Embeddable类比其他任何东西。查看EclipseLink 2.0.0的代码(无法找到您的版本的src),它表明NPE来自有关该类的元数据。如果我不得不作出有根据的猜测,我会说EclipseLink默默地失败了类加载(后来导致NPE),而Hibernate使用另一种机制来加载类(通过字节码编织或其他)。

+0

+1谢谢!因此,_in理论_你是否同意这是EclipseLink中的一个错误? – andyb 2011-05-13 19:05:10

+0

根据edarlozo的回答,这是一个要求,该类必​​须是顶级的,所以唯一的“bug”是EclipseLink的错误报告。 – 2011-05-16 09:42:44

相关问题