Spring boot, runnable jar can't load package-info.class

▼魔方 西西 提交于 2019-12-25 16:57:55

问题


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 etc. prepended to their package. If you actually need package level annotations you would need to get a bit more sophisticated than this crutch, though. But this works for me ¯\_(ツ)_/¯




回答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>&ndash;&gt;-->
                                    </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:


Nestor Fedyk solution helped me in resolving the issue.

please find the code below, i have added the solution to my hibernate config file

"exclude-unlisted-classes" "hibernate.archive.autodetection" properties added

  <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="rcsDataSource"/>
    <property name="persistenceUnitName" value="corePersistenceUnit"/>
    <property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter"/>
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.query.factory_class">org.hibernate.hql.internal.classic.ClassicQueryTranslatorFactory</prop>
            <prop key="hibernate.cache.use_second_level_cache">false</prop>
            <prop key="hibernate.cache.use_query_cache">false</prop>
            <prop key="hibernate.cache.region.factory_class">xxxx.xxxxxxxx.xxxx</prop>
            <prop key="hibernate.cache.provider_class">xxx.xxxxxxxx.xxxx</prop>
            <prop key="hibernate.cache.use_structured_entries">false</prop>
            <prop key="hibernate.generate_statistics">true</prop>
            <prop key="hibernate.default_batch_fetch_size">250</prop>            
            <prop key="hibernate.max_fetch_depth">5</prop>            
            <prop key="hibernate.jdbc.fetch_size">300</prop>
            <prop key="exclude-unlisted-classes">true</prop>
            <prop key="hibernate.archive.autodetection">"hbm"</prop>
        </props>
    </property>
    <property name="jpaDialect">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
    </property>
</bean>

I hope this helps




回答5:


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.



来源:https://stackoverflow.com/questions/43782191/spring-boot-runnable-jar-cant-load-package-info-class

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!