반응형
🚨오류
Caused by: 
org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'jpaAuditingHandler': 
Cannot resolve reference to bean 'jpaMappingContext' while setting constructor argument; 
nested exception is org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'jpaMappingContext': 
Invocation of init method failed; 
nested exception is java.lang.IllegalArgumentException: 
JPA metamodel must not be empty!

 

✍️원인

jpaAuditing 기능을 사용하기 위해 @EnableJPaAuditing을 Application에 선언

Spring 테스트에서 컨테이너를 사용하는 경우, 기본 애플리케이션 클래스(@SpringBootApplication이 붙은 클래스)를 항상 로드

Application 클래스에 @EnableJpaAuditing이 설정되어 있어서, 모든 테스트에서 JPA 관련 빈(EntityManager, JpaRepository 등)이 필요하게 됨

통합 테스트(@SpringBootTest)는 JPA 관련 빈을 전부 로드하므로 문제 없지만, @WebMvcTest는 컨트롤러 관련 빈만 로드하므로 JPA 빈이 없어서 오류 발생함

 

 

 

✅해결

1. @MokitoBean 추가

@Test
@DisplayName("회원가입 성공 테스트")
@MockitoBean(JpaMetamodelMappingContext.class)
void createUserSuccessTest() throws Exception {}

각각의 Test에 @MokitoBean을 선언해야하는 번거러움 존재

 

2. JpaAuditingConfig 파일 분리

@EnableJpaAuditing
@Configuration
public class JpaAuditingConfig {

}

 

 

 

📚참고

https://velog.io/@suujeen/Error-creating-bean-with-name-jpaAuditingHandler

 

Error creating bean with name 'jpaAuditingHandler':

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaAuditingHandler': Cannot resolve reference to bean 'jpaMappingContext' while setting constructor a...

velog.io

 

 

반응형
반응형

duplicateKeyException

Environment
Language: Java
DB: MySQL

 

오류

Caused by: java.lang.IllegalStateException: Duplicate key 400 BAD_REQUEST (attempted merging values DUPLICATED_EMAIL and NOT_EQUAL_PASSWORD)
	at java.base/java.util.stream.Collectors.duplicateKeyException(Collectors.java:135)
	at java.base/java.util.stream.Collectors.lambda$uniqKeysMapAccumulator$1(Collectors.java:182)

 

 

원인

DUPLICATED_EMAIL(HttpStatus.BAD_REQUEST, "이미 존재하는 이메일 입니다."),
NOT_EQUAL_PASSWORD(HttpStatus.BAD_REQUEST,"입력한 비밀번호가 상이합니다."),

// HttpStatus -> ErrorCode 조회
private static final Map<HttpStatus, ErrorCode> BY_HTTPSTATUS =
        Stream.of(values()).collect(Collectors.toMap(ErrorCode::getHttpStatus, e -> e));

public static Optional<ErrorCode> valueOfHttpStatus(HttpStatus httpStatus){
    return Optional.ofNullable(BY_HTTPSTATUS.get(httpStatus));
}

 

  • toMap()
    • If the mapped keys contain duplicates (according to Object.equals(Object)), an IllegalStateException is thrown when the collection operation is performed. If the mapped keys might have duplicates, use toMap(Function, Function, BinaryOperator) instead.
    • HttpStatus로부터 Enum을 조회하려고 할 때, Map을 활용하는데 이 때 key 값(= HttpStatus)이 중복될 경우, duplicate관련 IllegalStateException이 발생할 수 있음

 

해결

// HttpStatus -> ErrorCode 조회
private static final Map<HttpStatus, ErrorCode> BY_HTTPSTATUS =
        Stream.of(values()).collect(Collectors.toMap(ErrorCode::getHttpStatus, e -> e, ((e1, e2) -> e1)));
        // Stream.of(values()).collect(Collectors.toMap(ErrorCode::getHttpStatus, e -> e, ((e1, e2) -> e2)));

public static Optional<ErrorCode> valueOfHttpStatus(HttpStatus httpStatus){
    return Optional.ofNullable(BY_HTTPSTATUS.get(httpStatus));
}

 

  • toMap(Function, Function, BinaryOperator)
    • BinaryOperator에서 먼저 put할 데이터를 사용할지 나중에 put한 데이터를 사용할지 추가

 

📚 참고 자료

 

[Error/Exception] java.lang.IllegalStateException: Duplicate key ‘key로 저장하려는 값’ (attempted merging values ~~)

에러 발생java.lang.IllegalStateException: **Duplicate key 'key로 저장하려는 값'** (attempted merging values ~~) 오늘도 만난 에러,, 뜯어봐야 알겠지만 대충 봐도 key 값이 중복되어 발생한 에러다.  에러 원인에

hoehen-flug.tistory.com

 

반응형
반응형

EmptyResultDataAccessException

Environment
Language: Java
DB: MySQL

 

오류

Caused by: jakarta.persistence.NoResultException: No result found for query [select u from User u where u.email = :email]
	at org.hibernate.query.spi.AbstractSelectionQuery.getSingleResult(AbstractSelectionQuery.java:476)
	at com.msgs.user.repository.UserRepository.findByEmail(UserRepository.java:19)

 

 

원인

public Optional<User> findByEmail(String email) {
    User user = em.createQuery("select u from User u where u.email = :email", User.class)
            .setParameter("email", email)
            .getSingleResult();
    return Optional.ofNullable(user);
}

 

  • getSingleResult()
  1. 결과가 없을 경우, NoResultException 예외 발생
  2. 결과가 2개 이상일 경우, NonUniqueResultException 예외 발생

 

해결

public Optional<User> findByEmail(String email) {
    List<User> users = em.createQuery("select u from User u where u.email = :email", User.class)
            .setParameter("email", email)
            .getResultList();
    if (users.isEmpty()) {
        return Optional.empty();
    } else {
        return Optional.of(users.get(0));
    }
}

 

  • getSingleResult() → getResultList()

 

반응형
반응형

JdbcTypeRecommendationException

Environment

  • Language: Java
  • DB: H2 Database
  • IDE: IntelliJ

 

Problem

@Entity를 선언하고 table을 create할 때 발생

Caused by: org.hibernate.type.descriptor.java.spi.JdbcTypeRecommendationException: Could not determine recommended JdbcType for Java type 'jpabook.jpashop.domain.Delivery'

 

Cause of Problem

Hibernate가 엔티티의 필드에 대한 JDBC 타입을 결정하지 못할 때 발생

엔티티 필드와 데이터베이스 컬럼 간의 매핑이 충분히 명시되지 않았거나 잘못되었을 때 발생

관계 설정을 하지 않는다면, Hibernate는 해당 관계를 어떻게 매핑해야 하는지 알 수 없게 되어, Java의 데이터 타입을 SQL 데이터베이스의 데이터 타입에 매핑하지 못하고 JdbcTypeRecommendationException이 발생

 

Solution

  • Delivery Entity가 사용된 Entity에서 @OneToMany 등의 관계 설정이 제대로 이뤄졌는지 확인
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Entity
@Getter @Setter
public class Member {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "member_id")
    private Long id;

    private String name;

    @Embedded
    private Address address;

    @OneToMany(mappedBy = "member")
    private List<Order> orders = new ArrayList<>();

    private Delivery delivery;

}

 

📚 참고 자료

반응형
반응형

BeanCreationException

Environment

  • Language: Java
  • DB: H2 Database
  • IDE: IntelliJ

 

Problem

Entity에서 PK에 @Id를 설정하고, @GeneratedValue를 통해 자동으로 값을 부여하고자 할 때 발생

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: Could not instantiate id generator [entity-name=jpabook.jpashop.Member]

Caused by: org.hibernate.HibernateException: Could not fetch the SequenceInformation from the database

Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Column "start_value" not found [42122-224]

 

Cause of Problem

strategy 속성을 생략하면 기본적으로 GenerationType.AUTO가 사용됨

Hibernate가 데이터베이스에 맞는 적절한 전략을 자동으로 선택

H2 DB는 IDENTITY, SEQUENCE, TABLE 전략을 모두 지원하므로 IDENTITY, SEQUENCE, TABLE 중 1개가 선택

SEQUENCE없이 GenerationType.SEQUENCE가 실행되어 Could not instantiate id generator 오류가 발생한 것으로 추정

 

Solution

  • @GeneratedValue에 strategy GenerationType.IDENTITY 속성 추가
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.Getter;
import lombok.Setter;

@Entity
@Getter @Setter
public class Member {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
}
  • strategy 유형
    • GenerationType.AUTO
      • 기본값
      • 데이터베이스에 맞는 적절한 전략을 자동으로 선택
    • GenerationType.IDENTITY
      • PK 생성을 DB에 위임(예: MySQL-AUTO_INCREMENT)
      • PK에 null값을 넘기면 DB에서 자동으로 생성해줌
    • GenerationType.SEQUENCE
      • Sequence 객체를 생성해서 생성한 Sequence 객체에서 값을 가져와 PK값에 세팅
      • 주로 Oracle, H2에서 지원
    • GenerationType.TABLE
      • 키 생성 전용 테이블을 하나 만들어서 데이터베이스 시퀀스를 사용하는 것처럼 하는 전략
      • 시퀀스를 지원하지 않을 때 사용

 

cf. @Id package 확인

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import lombok.Getter;
import lombok.Setter;

@Entity
@Getter @Setter
public class Member {

    @Id @GeneratedValue
    private Long id;
    private String username;
}

@Id의 package 경로가 jakarta인지 확인

  • jakarta.persistence.Id
    • the annotation defined by JPA for all its implementations
    • JPA only applies for management of relational data
  • org.springframework.data.annotation.Id
    • currently used by Spring to support mapping for other non relational persistence databases or frameworks
    • it is normally used when dealing with other spring-data projects such as spring-data-mongodb, spring-data-solr, etc

 

📚 참고 자료

What's the difference between javax.persistence.Id and org.springframework.data.annotation.Id?
[JPA_Basic] 기본키 매핑
[JPA] H2의 @GeneratedValue 문제

반응형