可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
We use Spring boot with hibernate database mapping. The entities contains JSON columns mapped as a customized types defined using package-info.java file.
When we run the spring-project from Eclipse IDE everything is ok and we can call our web services.
When we generate an executable jar and we try to call our web services the following error is raised :
mai 04, 2017 1:35:00 PM org.apache.catalina.core.StandardWrapperValve invoke GRAVE: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.RuntimeException: Unable to execute job Test] with root cause java.lang.NoClassDefFoundError: BOOT-INF/classes/com/test/package-info (wrong name: com/test/package-info) at java.lang.ClassLoader.defineClass1(Native Method)
The file package-info.class is into the jar BOOT-INF/classes/com/test/package-info What can be wrong ?
Thanks for any help
回答1:
I solved this issue by disabling package scan and autodetection of classed for Hibernate
<persistence-unit name="sqlProvider" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> <class>com.example.package.dao</class> ......... <properties> <property name="exclude-unlisted-classes" value="true"/> <property name="hibernate.archive.autodetection" value="hbm" /> ......... </properties> ......... </persistence-unit>
回答2:
I didn't want to disable scanning as manually adding all classes to persistence.xml
wasn't an option. Since we do not actually use package level annotations for hibernate in our project, I created this little abomination:
package com.example; import org.hibernate.boot.archive.scan.internal.ScanResultImpl; import org.hibernate.boot.archive.scan.internal.StandardScanner; import org.hibernate.boot.archive.scan.spi.ScanEnvironment; import org.hibernate.boot.archive.scan.spi.ScanOptions; import org.hibernate.boot.archive.scan.spi.ScanParameters; import org.hibernate.boot.archive.scan.spi.ScanResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Collections; public class HibernateHackScanner extends StandardScanner { private static final Logger log = LoggerFactory.getLogger(HibernateHackScanner.class); @Override public ScanResult scan(ScanEnvironment environment, ScanOptions options, ScanParameters parameters) { log.info("Hack-Scanner is active, annotated packages will not be found by this scanner."); ScanResult scan = super.scan(environment, options, parameters); return new ScanResultImpl(Collections.emptySet(), scan.getLocatedClasses(), scan.getLocatedMappingFiles()); } }
Then I enabled this custom scanner in persistence.xml
:
<property name="hibernate.archive.scanner" value="com.example.HibernateHackScanner"/>
This scanner uses the standard scanner under the hood and simply discards all annotated packages which have boot_inf.classes
回答3:
I use cxf-codegen-plugin
to generate entites. In my case excluding package-info
class solved the problem. I deleted package-info.class
from project file, add extraargs to pom file like:
<plugin> <groupId>org.apache.cxf</groupId> <artifactId>cxf-codegen-plugin</artifactId> <version>${cxf.version}</version> <executions> <execution> <id>mvn s</id> <phase>generate-sources</phase> <configuration> <sourceRoot>${project.build.directory}/generated/cxf</sourceRoot> <sourceRoot>${basedir}/src/main/java</sourceRoot> <wsdlOptions> <wsdlOption> <wsdl>${basedir}/src/main/resources/wsdl/YOURWSDL.wsdl</wsdl> <wsdlLocation>classpath:wsdl/YOURWSDL.wsdl</wsdlLocation> <bindingFiles> <bindingFile>${basedir}/src/main/resources/wsdl/bindings.xml</bindingFile> </bindingFiles> </wsdlOption> <wsdlOption> <wsdl>${basedir}/src/main/resources/wsdl/YOURWSDL.wsdl</wsdl> <!--<extraargs>--> <!--<extraarg>-impl</extraarg>--> <!--<extraarg>-server</extraarg>--> <!--</extraargs>–>--> </wsdlOption> </wsdlOptions> <defaultOptions> <extraargs> <extraarg>-xjc-npa</extraarg> </extraargs> </defaultOptions> </configuration> <goals> <goal>wsdl2java</goal> </goals> </execution> </executions> </plugin>
and package file: mvn clean install spring-boot:repackage -DskipTests
. Now it works fine.
回答4:
You can extract the package containing the JAXB generated classes (that is the package containing the package-info
class) in an external jar. Move to the new project the JAXB related resources, too (e.g., the XSD file).
Now you can set such a jar as a dependency of the project producing the exacutable jar.
This way, my Spring Batch/Spring Boot project works when I run it from command line. I'm aware that it's not an optimal solution but, in my case, it works.