我创建了一个简单的quarkus(0.21.2版)应用程序,该应用程序将休眠orm与panache一起使用将实体保存到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
。
答案 0 :(得分:1)
似乎本地图像工具没有在本地图像中包含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
文件中,因为我不确定注释是否会包含所有使用的类按您的实体或仅按您的实体类。