Spring boot, runnable jar не может загрузить package-info.class
Мы используем загрузку Spring с отображением базы данных в спящем режиме. Объекты содержат столбцы JSON, отображаемые как настраиваемые типы, определенные с помощью файла package-info.java.
Когда мы запускаем Spring-проект из Eclipse IDE, все в порядке, и мы можем вызывать наши веб-сервисы.
Когда мы генерируем исполняемый файл jar и пытаемся вызвать наши веб-сервисы, возникает следующая ошибка:
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)
Файл package-info.class находится в jar-файле BOOT-INF/classes/com/test/package-info Что может быть не так?
Спасибо за любую помощь
4 ответа
Я решил эту проблему, отключив сканирование пакетов и автообнаружение классифицированных для 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>
Я не хотел отключать сканирование, так как вручную добавлял все классы в persistence.xml
не вариант Поскольку в нашем проекте мы фактически не используем аннотации на уровне пакетов для hibernate, я создал эту маленькую мерзость:
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());
}
}
Затем я включил этот пользовательский сканер в persistence.xml
:
<property name="hibernate.archive.scanner" value="com.example.HibernateHackScanner"/>
Этот сканер использует стандартный сканер под капотом и просто отбрасывает все аннотированные пакеты, которые имеют boot_inf.classes
и т. д. прилагается к их упаковке. Если вы действительно нуждаетесь в аннотациях на уровне пакетов, вам нужно будет немного сложнее, чем этот костыль. Но это работает для меня ¯\_(ツ)_/¯
Решение Нестора Федыка помогло мне решить проблему.
пожалуйста, найдите код ниже, я добавил решение в свой конфигурационный файл гибернации
"exclude-unlisted-classes" добавлены свойства "hibernate.archive.autodetection"
<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>
надеюсь, это поможет
Я использую cxf-codegen-plugin
генерировать энтиты. В моем случае исключая package-info
класс решил проблему. я удалил package-info.class
из файла проекта добавьте дополнительные аргументы в файл pom, например:
<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>
и файл пакета: mvn clean install spring-boot:repackage -DskipTests
, Теперь все отлично работает.
Мне удалось заставить его работать с модификацией решения Яна Тома:
package com.example;
import org.hibernate.boot.archive.scan.internal.PackageDescriptorImpl;
import org.hibernate.boot.archive.scan.internal.ScanResultImpl;
import org.hibernate.boot.archive.scan.internal.StandardScanner;
import org.hibernate.boot.archive.scan.spi.*;
import org.hibernate.boot.archive.spi.ArchiveDescriptorFactory;
import java.util.Set;
import java.util.stream.Collectors;
public class CustomHibernateScanner extends StandardScanner {
private static final String SPRING_BOOT_JAR_PREFIX = "BOOT-INF.classes.";
public CustomHibernateScanner() {
}
public CustomHibernateScanner(ArchiveDescriptorFactory value) {
super(value);
}
@Override
public ScanResult scan(ScanEnvironment environment, ScanOptions options, ScanParameters parameters) {
ScanResult result = super.scan(environment, options, parameters);
Set<PackageDescriptor> pkgDesc = result.getLocatedPackages().stream()
.map(this::fixPackageDescriptor)
.collect(Collectors.toSet());
return new ScanResultImpl(pkgDesc,
result.getLocatedClasses(),
result.getLocatedMappingFiles());
}
private PackageDescriptor fixPackageDescriptor(PackageDescriptor pd) {
if (pd.getName().startsWith(SPRING_BOOT_JAR_PREFIX)) {
return new PackageDescriptorImpl(pd.getName().substring(SPRING_BOOT_JAR_PREFIX.length()), pd.getStreamAccess());
}
return pd;
}
}
Он добавлен в
persistence.xml
как в исходном ответе. По сути, он удаляет префикс в имени дескриптора пакета, который вызывает исключение. Таким образом, он работает, и сканирование пакетов отключать не нужно.
Вы можете извлечь пакет, содержащий сгенерированные JAXB классы (то есть пакет, содержащий package-info
класс) во внешней банке. Переместите в новый проект также ресурсы, связанные с JAXB (например, файл XSD).
Теперь вы можете установить такую банку как зависимость проекта, создающего исполняемый банку.
Таким образом, мой проект Spring Batch/Spring Boot работает, когда я запускаю его из командной строки. Я знаю, что это не оптимальное решение, но в моем случае это работает.