일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 2023년회고
- 정보처리기사
- PCSQL
- programmers
- 코테
- 프로그래머스
- PCCE
- DB
- 자바알고리즘
- JAVA.
- 정처기
- sql
- SQL개발자시험
- 프로그래머스자바
- PCCP
- 코딩테스트
- 알고리즘
- 코딩역량인증시험
- python
- Oracle
- 2024년정보처리기사
- SQL개발
- JPAdata
- 개발자
- 자바
- 정보처리기사기출
- 정보처리기사대비
- JavaPersistenceApi
- java
- springboot3
- Today
- Total
똘이의 개발 Life
JPA org.hibernate.mapping.Value.getSelectables() value is null 본문
JPA org.hibernate.mapping.Value.getSelectables() value is null
또리또리똘 2024. 1. 23. 16:15프로젝트 스펙
Springboot 3.x , java 17 , spring jpa , spring web , spring validation , spring starter
As-Is
Entity 개발 후 프로젝트 구동 시 에러 발생
아래 에러 로그 확인
2024-01-23T14:19:38.064+09:00 INFO 26464 --- [ restartedMain] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default]
2024-01-23T14:19:38.159+09:00 INFO 26464 --- [ restartedMain] org.hibernate.Version : HHH000412: Hibernate ORM core version 6.4.1.Final
2024-01-23T14:19:38.207+09:00 INFO 26464 --- [ restartedMain] o.h.c.internal.RegionFactoryInitiator : HHH000026: Second-level cache disabled
2024-01-23T14:19:38.519+09:00 INFO 26464 --- [ restartedMain] o.s.o.j.p.SpringPersistenceUnitInfo : No LoadTimeWeaver setup: ignoring JPA class transformer
2024-01-23T14:19:38.936+09:00 WARN 26464 --- [ restartedMain] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Cannot invoke "org.hibernate.mapping.Value.getSelectables()" because "value" is null
2024-01-23T14:19:38.939+09:00 INFO 26464 --- [ restartedMain] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2024-01-23T14:19:38.954+09:00 INFO 26464 --- [ restartedMain] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
2024-01-23T14:19:38.958+09:00 INFO 26464 --- [ restartedMain] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
2024-01-23T14:19:38.971+09:00 INFO 26464 --- [ restartedMain] .s.b.a.l.ConditionEvaluationReportLogger :
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2024-01-23T14:19:38.994+09:00 ERROR 26464 --- [ restartedMain] o.s.boot.SpringApplication : Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Cannot invoke "org.hibernate.mapping.Value.getSelectables()" because "value" is null
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1773) ~[spring-beans-6.1.3.jar:6.1.3]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:599) ~[spring-beans-6.1.3.jar:6.1.3]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[spring-beans-6.1.3.jar:6.1.3]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) ~[spring-beans-6.1.3.jar:6.1.3]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.1.3.jar:6.1.3]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) ~[spring-beans-6.1.3.jar:6.1.3]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-6.1.3.jar:6.1.3]
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1231) ~[spring-context-6.1.3.jar:6.1.3]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:949) ~[spring-context-6.1.3.jar:6.1.3]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:624) ~[spring-context-6.1.3.jar:6.1.3]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[spring-boot-3.2.2.jar:3.2.2]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-3.2.2.jar:3.2.2]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456) ~[spring-boot-3.2.2.jar:3.2.2]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:334) ~[spring-boot-3.2.2.jar:3.2.2]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1354) ~[spring-boot-3.2.2.jar:3.2.2]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343) ~[spring-boot-3.2.2.jar:3.2.2]
at com.evzone.proxyapi.ProxyApiApplication.main(ProxyApiApplication.java:11) ~[main/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:50) ~[spring-boot-devtools-3.2.2.jar:3.2.2]
Caused by: java.lang.NullPointerException: Cannot invoke "org.hibernate.mapping.Value.getSelectables()" because "value" is null
at org.hibernate.mapping.Constraint.addColumns(Constraint.java:117) ~[hibernate-core-6.4.1.Final.jar:6.4.1.Final]
at org.hibernate.mapping.PersistentClass.createPrimaryKey(PersistentClass.java:427) ~[hibernate-core-6.4.1.Final.jar:6.4.1.Final]
at org.hibernate.boot.model.internal.CreateKeySecondPass.doSecondPass(CreateKeySecondPass.java:33) ~[hibernate-core-6.4.1.Final.jar:6.4.1.Final]
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1815) ~[hibernate-core-6.4.1.Final.jar:6.4.1.Final]
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1770) ~[hibernate-core-6.4.1.Final.jar:6.4.1.Final]
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:332) ~[hibernate-core-6.4.1.Final.jar:6.4.1.Final]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1432) ~[hibernate-core-6.4.1.Final.jar:6.4.1.Final]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1503) ~[hibernate-core-6.4.1.Final.jar:6.4.1.Final]
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:75) ~[spring-orm-6.1.3.jar:6.1.3]
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:376) ~[spring-orm-6.1.3.jar:6.1.3]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409) ~[spring-orm-6.1.3.jar:6.1.3]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:396) ~[spring-orm-6.1.3.jar:6.1.3]
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:352) ~[spring-orm-6.1.3.jar:6.1.3]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1820) ~[spring-beans-6.1.3.jar:6.1.3]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1769) ~[spring-beans-6.1.3.jar:6.1.3]
... 21 common frames omitted
Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0.
You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.
For more on this, please refer to https://docs.gradle.org/8.5/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation.
Caused by: java.lang.NullPointerException: Cannot invoke "org.hibernate.mapping.Value.getSelectables()" because "value" is null
에러 요약
Caused by: java.lang.NullPointerException: Cannot invoke "org.hibernate.mapping.Value.getSelectables()" because "value" is null
hibernate 쪽에 value 값 하나가 null 인 것 같은데
다른 프로젝트는 잘 돌아간다.
무엇이 문제일까...
Challenge
나는 뛰어난 개발자는 아니지만 3년 7개월 짜리 눈치 밥이 있다.
at org.hibernate.mapping.Constraint.addColumns(Constraint.java:117) ~
public void addColumns(Value value) {
for ( Selectable selectable : value.getSelectables() ) {
if ( selectable.isFormula() ) {
throw new MappingException( "constraint involves a formula: " + name );
}
else {
addColumn( (Column) selectable );
}
}
}
at org.hibernate.mapping.PersistentClass.createPrimaryKey(PersistentClass.java:427) ~
public void createPrimaryKey() {
//Primary key constraint
final Table table = getTable();
final PrimaryKey pk = new PrimaryKey( table );
pk.setName( PK_ALIAS.toAliasString( table.getName() ) );
pk.addColumns( getKey() );
table.setPrimaryKey( pk );
}
대충 에러 로그를 보니 Colums , PK 뭐 이런 쪽에서 에러가 나오는 것 같다.
Entity쪽에서 문제가 일어난 것 같은데...
Entity를 다 만들고 수정하자는 나의 생각은 잘못되었다..
여러분 JPA Entity 개발 시 점진적으로 DB 생성되는거 보면서 개발하세요...
찾고 찾던 와중 눈에 들어오는 코드...
// 이거 아닐 듯?
@OneToOne( fetch = LAZY , cascade = CascadeType.ALL )
@JoinColumn( name = "charger_idx" )
private ChargerStatus chargerStatus;
@OneToOne( fetch = LAZY , cascade = CascadeType.ALL )
@JoinColumn( name = "charger_idx" )
private ChargerMode chargerMode;
@OneToOne( fetch = LAZY , cascade = CascadeType.ALL )
@JoinColumn( name = "charger_idx" )
private ChargerConn chargerConn;
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class ChargerConn {
@Id
@OneToOne( mappedBy = "charger" , fetch = FetchType.LAZY )
@JoinColumn( name = "charger_idx" )
private Charger charger;
//---- 생략 -----//
}
찾았다 범인
위 코드가 잘 못된 것 같았다.
내가 원하는 구조가 따로 있었다...
ChargerStatus , ChargerConn , ChargerMode 의 PK 자체를 charger_idx로 사용하는 것이다.
예를 들면
charger_idx | name | 위치 | 생성일시 | charger_status | charger_mode | charger_conn | |
1 | A | 강남 | 2024-01-23 | READY | STOP | ONLINE | |
2 | B | 강서 | 2024-01-21 | WORKING | RUN | OFFLINE |
이런식으로 되어 있는 것을 정규화 해서
charger_idx | name | 위치 | 생성일시 |
1 | A | 강남 | 2024-01-23 |
2 | B | 강서 | 2024-01-21 |
ChargerStatus
charger_idx | charger_status |
1 | READY |
2 | WORKING |
ChargerMode
charger_idx | charger_mode |
1 | STOP |
2 | RUN |
ChargerConn
charger_idx | charger_conn |
1 | On |
2 | OFF |
이런식으로 각 테이블 마다 charger_idx 를 키 값으로 사용하고 싶었다.
To-Be
첫번째 해결 방식
package com.evzone.proxyapi.entity.charger;
import com.evzone.proxyapi.entity.ProxyServer;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class ChargerConn {
@Id
@GeneratedValue
@Column(name = "charger_conn_idx")
private Long id;
@OneToOne( mappedBy = "chargerConn" , fetch = FetchType.LAZY )
private Charger charger;
//--- 생략 ---- //
}
이런 식으로 PK를 하나 생성해줬다.
그런데 정말 저기서 따로 PK 값을 갖을 필요가 없는데... 완전 리소스 낭비
키값이 Charger 객체의 charger_idx 가 되게 해야 한다.
두번 째 해결
은 내가 혼자 삽질하면서 Entity 맵핑쪽을 좀 파봐야겠다.
마무리
JPA 핵심은 도메인 모델 설계 ~ Entity Mapping 이 제일 핵심 같다.
뭔가 설계부터 착착 제대로 조립해야 나중에 강력한 JPA - QueryDSL 의 맛? 을 볼 수 있을 것 같은...
사실 첫 술에 배부를 순 없다.
나름 강의 보고 실무에 적용해보려 했으나 해당되지 않는 것도 좀 있는 것 같아서
혼자 삽질을 좀 해봐야 겠다.
퇴근해야지~
'Back-End > JPA' 카테고리의 다른 글
[ 자바 ORM 표준 JPA 프로그래밍 기본편 ] 세션 5 연관 관계 맵핑 기초 (0) | 2024.01.09 |
---|