Spring-boot 및 spring-data-jpa가 로드된 경우 최대 절전 모드에서 JPA 2.1 컨버터를 로드하지 못함
UUID를 이진 대신 문자열로 전송하는 사용자 지정 변환기가 있습니다.
package de.kaiserpfalzEdv.commons.jee.db;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import java.util.UUID;
@Converter(autoApply = true)
public class UUIDJPAConverter implements AttributeConverter<UUID, String> {
@Override
public String convertToDatabaseColumn(UUID attribute) {
return attribute.toString();
}
@Override
public UUID convertToEntityAttribute(String dbData) {
return UUID.fromString(dbData);
}
}
변환기(특히 시간/날짜 처리를 위한 다른 변환기)는 라이브러리 .jar 파일에 있습니다.
그러면 .jar 파일에 엔티티가 있습니다.예를 들어 다음과 같습니다.
package de.kaiserpfalzEdv.office.core.security;
import de.kaiserpfalzEdv.commons.jee.db.OffsetDateTimeJPAConverter;
import de.kaiserpfalzEdv.commons.jee.db.UUIDJPAConverter;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import javax.persistence.Column;
import javax.persistence.Convert;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
@Entity
@Table(
name = "tickets"
)
public class SecurityTicket implements Serializable {
private final static ZoneId TIMEZONE = ZoneId.of("UTC");
private final static long DEFAULT_TTL = 600L;
private final static long DEFAULT_RENEWAL = 600L;
@Id @NotNull
@Column(name = "id_", length=50, nullable = false, updatable = false, unique = true)
@Convert(converter = UUIDJPAConverter.class)
private UUID id;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "account_id_", nullable = false, updatable = false, unique = true)
private Account account;
@Convert(converter = OffsetDateTimeJPAConverter.class)
@Column(name = "created_", nullable = false, updatable = false)
private OffsetDateTime created;
@Convert(converter = OffsetDateTimeJPAConverter.class)
@Column(name = "validity_", nullable = false, updatable = false)
private OffsetDateTime validity;
@Deprecated
public SecurityTicket() {
}
public SecurityTicket(@NotNull final Account account) {
id = UUID.randomUUID();
this.account = account;
created = OffsetDateTime.now(TIMEZONE);
validity = created.plusSeconds(DEFAULT_TTL);
}
public void renew() {
validity = OffsetDateTime.now(TIMEZONE).plusSeconds(DEFAULT_RENEWAL);
}
public boolean isValid() {
OffsetDateTime now = OffsetDateTime.now(TIMEZONE);
System.out.println(validity.toString() + " is hopefully after " + now.toString());
return validity.isAfter(now);
}
public UUID getId() {
return id;
}
public OffsetDateTime getValidity() {
return validity;
}
public String getAccountName() {
return account.getAccountName();
}
public String getDisplayName() {
return account.getDisplayName();
}
public Set<String> getRoles() {
HashSet<String> result = new HashSet<>();
account.getRoles().forEach(t -> result.add(t.getDisplayNumber()));
return Collections.unmodifiableSet(result);
}
public Set<String> getEntitlements() {
return Collections.unmodifiableSet(new HashSet<>());
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (obj == this) {
return true;
}
if (obj.getClass() != getClass()) {
return false;
}
SecurityTicket rhs = (SecurityTicket) obj;
return new EqualsBuilder()
.append(this.id, rhs.id)
.isEquals();
}
@Override
public int hashCode() {
return new HashCodeBuilder()
.append(id)
.toHashCode();
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
.append("id", id)
.append("account", account)
.append("validity", validity)
.toString();
}
}
메이븐 및 테스트를 통해 통합 테스트를 실행할 때 데이터베이스는 매우 잘 작동합니다.그러나 애플리케이션(세 번째 .jar 파일)을 시작하면 다음과 같은 불쾌한 예외가 발생합니다.
Caused by: org.hibernate.HibernateException: Wrong column type in kpoffice.tickets for column id_. Found: varchar, expected: binary(50)
at org.hibernate.mapping.Table.validateColumns(Table.java:372)
at org.hibernate.cfg.Configuration.validateSchema(Configuration.java:1338)
at org.hibernate.tool.hbm2ddl.SchemaValidator.validate(SchemaValidator.java:175)
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:525)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1859)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:852)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:845)
at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.withTccl(ClassLoaderServiceImpl.java:398)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:844)
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:60)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:343)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:318)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1625)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1562)
... 120 more
변환의 autoApply가 작동하지 않습니다.변환기를 클래스와 속성 자체에 주석을 달려고 했습니다.그러나 변환기는 사용되지 않습니다.그러나 hibernate 특정 주석을 통해 hibernate UUID 유형을 추가했을 때 동일한 속성에 대한 변환기와 hibernate 유형 정의를 가질 수 없다는 불만이 제기되었습니다.따라서 최대 절전 모드는 변환기 구성을 읽습니다.
Envers 사용 시 JPA 2.1 컨버터가 작동하지 않습니다.하지만 저는 제 소프트웨어에서 엔버를 사용하지 않습니다.
내가 뭘 잘못하고 있는지 아는 사람이 있었으면 좋겠어요...
Andy Wilkinson은 정답을 주었습니다.스펙을 읽는 것은 많은 경우에 도움이 됩니다.
JPA 2.1 변환기는 다음에 적용되지 않습니다.@Id
주석이 달린 속성.
감사합니다 Andy.
또 다른 옵션은 다음과 같이 변환 로직을 대체 게터/세터에 내장하는 것입니다.
public class SecurityTicket implements Serializable
{
...
private UUID id;
@Transient
public UUID getUUID()
{
return id;
}
@Id @NotNull
@Column(name = "id_", length=50, nullable = false, updatable = false, unique = true)
public String getID()
{
return id.toString();
}
public void setUUID( UUID id )
{
this.id = id;
}
public void setID( String id )
{
this.id = UUID.fromString( id );
}
...
그@Transient
주석은 JPA가 별도의 UUID 속성이 있다고 생각하지 않도록 이 게터를 무시하도록 지시합니다.우아하지는 않지만 UUID를 PK로 사용하는 클래스에서 JPA를 사용하는 데 효과가 있었습니다.setId(String) 메서드를 통해 다른 코드가 잘못된 값을 설정할 위험이 있지만 이 방법이 유일한 해결 방법인 것 같습니다.이 방법을 보호/비공개할 수 있습니까?
일반적인 Java 코드는 다른 인수 유형을 기반으로 동일한 이름을 가진 설정자를 구별할 수 있지만, JPA는 다르게 이름을 지정하지 않으면 불만을 제기합니다.
JPA가 Converters on Ids를 지원하지 않거나 표준 변환 방법(예: toString/fromString, intValue/parseInt 등)을 사용하는 클래스에 변환기를 요구하지 않는 JAXB 규약을 따르지 않는 것은 짜증나는 일입니다.
언급URL : https://stackoverflow.com/questions/28337798/hibernate-fails-to-load-jpa-2-1-converter-when-loaded-with-spring-boot-and-sprin
'programing' 카테고리의 다른 글
Jquery는 첫 번째 ax 함수 호출이 완전히 완료된 후 다른 ax 함수를 계속합니다. (0) | 2023.09.08 |
---|---|
각도 2: 상위 구성 요소에서 RouteParams 가져오기 (0) | 2023.09.03 |
사용자가 단추를 두 번 클릭하지 않도록 하려면 어떻게 해야 합니까? (0) | 2023.09.03 |
dig(DNS Lookup) 윈도우즈에서 DNS 서버 지정 (0) | 2023.09.03 |
하나의 요소에 두 개의 CSS3 박스 그림자를 사용하는 방법이 있습니까? (0) | 2023.09.03 |