2011-05-13 89 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

相關問題