java - Quarkus 测试在本机中失败,因为找不到 DayOfWeek
问题描述
我创建了一个简单的 quarkus(版本 0.21.2)应用程序,它使用带有 panache 的 hibernate orm 将实体保存到 h2 数据库。该实体包括一个ElementCollection
。DaysOfWeek
我还创建了一些测试以确保 CURD 正常工作。测试一切正常,但是当我自然地运行它们时,我得到以下异常:
Exception in thread "main" java.lang.RuntimeException: Failed to start quarkus
at io.quarkus.runner.ApplicationImpl1.doStart(ApplicationImpl1.zig:126)
at io.quarkus.runtime.Application.start(Application.java:91)
at io.quarkus.runtime.Application.run(Application.java:204)
at io.quarkus.runner.GeneratedMain.main(GeneratedMain.zig:34)
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory
at io.quarkus.hibernate.orm.runtime.boot.FastBootEntityManagerFactoryBuilder.persistenceException(FastBootEntityManagerFactoryBuilder.java:113)
at io.quarkus.hibernate.orm.runtime.boot.FastBootEntityManagerFactoryBuilder.build(FastBootEntityManagerFactoryBuilder.java:67)
at io.quarkus.hibernate.orm.runtime.FastBootHibernatePersistenceProvider.createEntityManagerFactory(FastBootHibernatePersistenceProvider.java:54)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:79)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:54)
at io.quarkus.hibernate.orm.runtime.JPAConfig$LazyPersistenceUnit.get(JPAConfig.java:109)
at io.quarkus.hibernate.orm.runtime.JPAConfig.startAll(JPAConfig.java:57)
at io.quarkus.hibernate.orm.runtime.HibernateOrmRecorder.startAllPersistenceUnits(HibernateOrmRecorder.java:77)
at io.quarkus.deployment.steps.HibernateOrmProcessor$startPersistenceUnits19.deploy_0(HibernateOrmProcessor$startPersistenceUnits19.zig:51)
at io.quarkus.deployment.steps.HibernateOrmProcessor$startPersistenceUnits19.deploy(HibernateOrmProcessor$startPersistenceUnits19.zig:70)
at io.quarkus.runner.ApplicationImpl1.doStart(ApplicationImpl1.zig:90)
... 3 more
Caused by: org.hibernate.MappingException: Could not create DynamicParameterizedType for type: org.hibernate.type.EnumType
at org.hibernate.mapping.SimpleValue.createParameterImpl(SimpleValue.java:768)
at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:470)
at org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:455)
at org.hibernate.mapping.Collection.validate(Collection.java:315)
at org.hibernate.boot.internal.MetadataImpl.validate(MetadataImpl.java:347)
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:461)
at io.quarkus.hibernate.orm.runtime.boot.FastBootEntityManagerFactoryBuilder.build(FastBootEntityManagerFactoryBuilder.java:65)
... 12 more
Caused by: org.hibernate.boot.registry.classloading.spi.ClassLoadingException: Unable to load class [java.time.DayOfWeek]
at io.quarkus.hibernate.orm.runtime.service.FlatClassLoaderService.classForName(FlatClassLoaderService.java:39)
at org.hibernate.mapping.SimpleValue.createParameterImpl(SimpleValue.java:755)
... 18 more
Caused by: java.lang.ClassNotFoundException: java.time.DayOfWeek
at com.oracle.svm.core.hub.ClassForNameSupport.forName(ClassForNameSupport.java:60)
at java.lang.Class.forName(DynamicHub.java:1174)
at io.quarkus.hibernate.orm.runtime.service.FlatClassLoaderService.classForName(FlatClassLoaderService.java:37)
... 19 more
我的实体如下所示:
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.validation.constraints.NotNull;
import java.time.DayOfWeek;
import java.time.LocalTime;
import java.util.*;
import static org.hibernate.annotations.CascadeType.ALL;
@Entity
@JsonIgnoreProperties(ignoreUnknown = true)
public class OpeningTimes extends PanacheEntityBase {
@Id
@GeneratedValue(generator = "UUID")
@GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
private UUID id;
@NotNull
private String name;
private String description;
private LocalTime timeFrom;
private LocalTime timeTo;
@ElementCollection
@Cascade(value = {ALL})
private Collection<DayOfWeek> daysOfWeek;
/**
* DO NOT USE! ONLY FOR JPA!
*/
OpeningTimes() {
super();
name = "";
}
@JsonCreator
public OpeningTimes(
@JsonProperty("name") String name,
@JsonProperty("timeFrom") LocalTime timeFrom,
@JsonProperty("timeTo") LocalTime timeTo,
@JsonProperty("daysOfWeek") Collection<DayOfWeek> daysOfWeek) {
this.name = name;
this.timeFrom = timeFrom;
this.timeTo = timeTo;
this.daysOfWeek = new HashSet<>(daysOfWeek);
}
public OpeningTimes(String name, LocalTime from, LocalTime to, DayOfWeek... daysOfWeek) {
this(name, from, to, new ArrayList<>(Arrays.asList(daysOfWeek)));
}
public LocalTime getTimeFrom() {
return timeFrom;
}
public void setTimeFrom(LocalTime timeFrom) {
this.timeFrom = timeFrom;
}
public LocalTime getTimeTo() {
return timeTo;
}
public void setTimeTo(LocalTime timeTo) {
this.timeTo = timeTo;
}
public Collection<DayOfWeek> getDaysOfWeek() {
return daysOfWeek;
}
public void setDaysOfWeek(Set<DayOfWeek> daysOfWeek) {
this.daysOfWeek = daysOfWeek;
}
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof OpeningTimes)) return false;
OpeningTimes that = (OpeningTimes) o;
return Objects.equals(getId(), that.getId())
&& Objects.equals(getName(), that.getName())
&& Objects.equals(getDescription(), that.getDescription())
&& Objects.equals(getTimeFrom(), that.getTimeFrom())
&& Objects.equals(getTimeTo(), that.getTimeTo())
&& Objects.equals(getDaysOfWeek(), that.getDaysOfWeek());
}
@Override
public int hashCode() {
return Objects.hash(
getId(), getName(), getDescription(), getTimeFrom(), getTimeTo(), getDaysOfWeek());
}
@Override
public String toString() {
return "OpeningTimes{"
+ "id="
+ id
+ ", name='"
+ name
+ '\''
+ ", description='"
+ description
+ '\''
+ ", timeFrom="
+ timeFrom
+ ", timeTo="
+ timeTo
+ ", daysOfWeek="
+ daysOfWeek
+ '}';
}
public void merge(OpeningTimes openingTimes) {
this.name = openingTimes.name;
this.description = openingTimes.description;
this.timeFrom = openingTimes.timeFrom;
this.timeTo = openingTimes.timeTo;
this.daysOfWeek = openingTimes.daysOfWeek;
}
}
这是我的测试:
import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.h2.H2DatabaseTestResource;
import io.quarkus.test.junit.QuarkusTest;
import io.restassured.http.ContentType;
import io.restassured.mapper.ObjectMapperType;
import io.restassured.mapper.TypeRef;
import io.restassured.response.Response;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.transaction.Transactional;
import java.time.DayOfWeek;
import java.time.LocalTime;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
@QuarkusTest
@QuarkusTestResource(H2DatabaseTestResource.class)
class OpeningsResourceTest {
private static final Logger LOG = LoggerFactory.getLogger(OpeningsResourceTest.class);
@Test
void testSaveOpening() {
OpeningTimes opening =
new OpeningTimes(
"Test opening", LocalTime.MIN, LocalTime.NOON, DayOfWeek.MONDAY, DayOfWeek.THURSDAY);
Response response =
given()
.when()
.contentType(ContentType.JSON)
.body(opening, ObjectMapperType.JACKSON_2)
.post("/service/events/openings");
LOG.debug(response.andReturn().body().prettyPrint());
OpeningTimes responseObject = response.then().statusCode(200).extract().as(OpeningTimes.class);
// Set the id because its generated on saving
opening.setId(responseObject.getId());
assertThat(responseObject, equalTo(opening));
}
@Test
void testGetOpening() {
OpeningTimes testdata = saveTestdata().get(0);
Response response = given().when().get("/service/events/openings/{id}/", testdata.getId());
OpeningTimes responseObject = response.then().statusCode(200).extract().as(OpeningTimes.class);
assertThat(responseObject, equalTo(testdata));
}
@Test
void testDeleteOpening() {
OpeningTimes testdata = saveTestdata().get(0);
// Delete
given()
.when()
.delete("/service/events/openings/{id}/", testdata.getId())
.then()
.statusCode(204);
// Check if it is deleted
given().when().get("/service/events/openings/{id}/", testdata.getId()).then().statusCode(204);
}
@Test
void testChangeOpening() {
OpeningTimes testdata = saveTestdata().get(0);
testdata.setDescription("Example description");
Response response =
given()
.when()
.contentType(ContentType.JSON)
.body(testdata, ObjectMapperType.JACKSON_2)
.put("/service/events/openings/");
LOG.debug(response.andReturn().body().prettyPrint());
response.then().statusCode(200).extract().as(OpeningTimes.class);
OpeningTimes changedOpening =
given()
.when()
.get("/service/events/openings/{id}", testdata.getId())
.then()
.statusCode(200)
.extract()
.as(OpeningTimes.class);
assertThat(changedOpening, is(testdata));
}
private List<OpeningTimes> saveTestdata() {
OpeningTimes opening1 =
new OpeningTimes(
"Test opening", LocalTime.MIN, LocalTime.NOON, DayOfWeek.MONDAY, DayOfWeek.THURSDAY);
OpeningTimes opening2 =
new OpeningTimes("Test opening 2", LocalTime.MIN, LocalTime.NOON, DayOfWeek.FRIDAY);
opening1 =
given()
.contentType(ContentType.JSON)
.body(opening1, ObjectMapperType.JACKSON_2)
.post("/service/events/openings")
.then()
.extract()
.as(OpeningTimes.class);
opening2 =
given()
.contentType(ContentType.JSON)
.body(opening2, ObjectMapperType.JACKSON_2)
.post("/service/events/openings")
.then()
.extract()
.as(OpeningTimes.class);
return Arrays.asList(opening1, opening2);
}
@Test
void testGetAll() {
List<OpeningTimes> testdata = saveTestdata();
Collection<OpeningTimes> openings =
given()
.when()
.get("/service/events/openings")
.then()
.statusCode(200)
.extract()
.as(new TypeRef<Collection<OpeningTimes>>() {});
assertThat(openings, is(testdata));
}
@AfterEach
@Transactional
void cleanUpDatabase() {
// Delete all won't work because of the element collection
OpeningTimes.findAll().stream().forEach(PanacheEntityBase::delete);
}
}
和本机测试:
import io.quarkus.test.junit.SubstrateTest;
@SubstrateTest
public class NativeOpeningsResourceIT extends OpeningsResourceTest {
// Execute the same tests but in native mode.
}
我不知道为什么它没有找到java.time.DayOfWeek
.
解决方案
似乎本机图像工具没有java.time.DayOfWeek
在本机图像中包含该类。SubstratVM 在一个封闭的世界中工作,只能访问在本机映像编译期间发现的类或专门注册用于反射的类。
您可以按照此部分注册反射java.time.DayOfWeek
课程:https ://quarkus.io/guides/writing-native-applications-tips#registering-for-reflection 。
您可以尝试在 Entity 类上使用注释,但我认为您需要java.time.DayOfWeek
在reflection-config.json
文件中包含该类,因为我不确定该注释是包含您的 Entity 使用的所有类还是仅包含您的 Entity 类。
推荐阅读
- java - Hibernate 逆向工程 INTEGER 不同大小
- postgresql - 连接来自多个表的不同列并组合结果;联合方法成本太高,需要替代方法 - Postgresql
- fortran - 在 fortran 中跟踪内存使用情况
- google-analytics - Google Analytics(分析)应用+网络媒体资源的 screen_name 限制
- angular - 如何在没有路由器的情况下动态延迟加载模块 - Angular 9
- php - 如何使用另一个数组键创建一个新数组?
- c# - 坚持以正确的方式解析 JSON
- javascript - 在 IIFE 中声明一个分配给具有相同名称的 var 的函数是什么意思?
- excel - 在语句中动态使用标识列
- javascript - 四舍五入到下一个整数javascript