Не найдено конвертера, способного преобразовывать из типа [java.lang .String] в тип [@Autowired @ManyToOne @JoinColumn com.papertrue.country .Страна]

#java #spring-boot #jpa #spring-data-jpa

#java #spring-boot #jpa #spring-data-jpa

Вопрос:

Итак, я довольно новичок в JPA, и я застрял при отображении объекта в другой объект. Вот моя пользовательская сущность:

 package com.papertrue.user;

import com.papertrue.country.Country;
import com.papertrue.currency.Currency;

@Entity
@ConfigurationProperties("user")
@Table(name = "users")
public class User {

    @Id
    @Column(name = "id")
    private String userId;

    private String name;

    @Column(name = "phone_ext")
    private String phoneExt;

    @Column(name = "phone_no")
    private String phoneNo;

    private String email;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "country")
    private Country country;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "currency")
    private Currency currency;

    @Column(name = "fb_id")
    private String facebookId;

    @Column(name = "google_id")
    private String googleId;

    @Column(name = "current_balance")
    private int currentBalance;

    @Column(name = "is_enabled")
    private boolean isEnabled;

    @Column(name = "free_sample_used")
    private boolean isfreeSampleUsed;

    @Column(name = "client_id")
    private String clientId;

}
  

Объект моей страны:

 package com.papertrue.country;

import com.papertrue.currency.Currency;

@Entity
@ConfigurationProperties("country")
@Table(name = "countries")
public class Country {

    @Id
    private String code;

    private String name;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "currency")
    private Currency currency;

    @Column(name = "isd_ext")
    private String ISDExt;

    @Enumerated(EnumType.STRING)
    private transient Region region;
}
  

И мой объект валюты:

 package com.papertrue.currency;

@Entity
@ConfigurationProperties("currency")
@Table(name = "currencies")
public class Currency {

    @Id
    private String code;

    private String symbol;

    private String name;

    private int multiplier;

    @Column(name = "minVal")
    private int minValue;

}
  

Так что это работает, когда я сопоставляю валюту с-в объекте Country, но это почему-то не так, когда я делаю то же самое с пользователем и страной. Я получаю org.springframework.core.convert.ConverterNotFoundException . Вот ошибка:

 java.lang.IllegalStateException: Failed to load ApplicationContext
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:132) ~[spring-test-5.3.0.jar:5.3.0]
Caused by: org.springframework.boot.context.properties.ConfigurationPropertiesBindException: Error creating bean with name 'user-com.papertrue.user.User': Could not bind properties to 'User' : prefix=user, ignoreInvalidFields=false, ignoreUnknownFields=true; nested exception is org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'user.country' to com.papertrue.country.Country
    ... 70 common frames omitted
Caused by: org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'user.country' to com.papertrue.country.Country
    ... 89 common frames omitted
Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.String] to type [@javax.persistence.ManyToOne @javax.persistence.JoinColumn com.papertrue.country.Country]
    ... 105 common frames omitted
  

And this is happening while I’m running the test:

 package com.papertrue;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.context.SpringBootTest;

import com.papertrue.exceptions.PaperTrueUserNotFoundException;
import com.papertrue.user.UserService;

@SpringBootTest
public class UserServiceTest {

    @Autowired
    private UserService userService;

    @Test
    public void contextLoads() {
        // Testing getEmailInstance
        System.out.println("====== getEmailInstance() ======");
        try {
            System.out.println(userService.getEmailInstance("text@papertrue.com").getName());
        } catch (PaperTrueUserNotFoundException e) {
            e.printStackTrace();
        }

    }

    @SpringBootApplication
    static class TestConfiguration {
    }

}
  

Служба UserService:

 package com.papertrue.user;

import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Service;

import com.papertrue.exceptions.PaperTrueUserNotFoundException;

@Service
@EnableConfigurationProperties(User.class)
public class UserService {

    @Autowired
    private UserRepository userRepository;

    /**
     * Returns user whose email matches to parameter email's value.
     * 
     * @param email
     * @return
     * @throws PaperTrueUserNotFoundException
     */
    public User getEmailInstance(String email) throws PaperTrueUserNotFoundException {

        Optional<User> optional = userRepository.findByEmail(email);

        if (optional.isPresent()) {
            return optional.get();
        }

        throw new PaperTrueUserNotFoundException("User Not Found");
    }

}
  

И репозиторий для справки:

 package com.papertrue.user;

import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface UserRepository extends JpaRepository<User, String> {

    Optional<User> findByEmail(String email);
}
  

Ответ №1:

Исключение сообщает вам, что оно не может установить свойства конфигурации, как рекомендовано @ConfigurationProperties . Потому что для country он имеет String значение (возможно, в application.properties ), но нуждается в Country и не имеет конвертера для этого.

Возникает вопрос: «Чего вы пытаетесь достичь с @ConfigurationProperties помощью аннотаций?»

По крайней мере, неортодоксально использовать его для объектов JPA, потому что beans и entities — это обычно две совершенно разные вещи.

Поэтому вам следует либо удалить @ConfigurationProperties аннотации, либо зарегистрировать пользовательский конвертер, как описано здесь: https://www.logicbig.com/tutorials/spring-framework/spring-boot/custom-configuration-properties-binding.html

Комментарии:

1. Это проект библиотеки, и я буду импортировать этот проект в другой проект, следовательно @ConfigurationProperties , аннотацию, и когда я его удаляю, я получаю java.lang.IllegalStateException: No ConfigurationProperties annotation found on 'com.papertrue.country.Country'.

2. Я не понимаю, как это объясняет цель @ConfigurationProperties

3. Я следил за этой статьей, чтобы создать проект библиотеки: spring.io/guides/gs/multi-module/#_create_the_library_project и там говорится, что для того, чтобы сделать его настраиваемым в стандартной идиоме Spring Boot (с помощью application.properties ), вы также можете добавить класс @ConfigurationProperties . Приложение выдает исключение, если я его удаляю.

4. Это относится к конфигурациям или компонентам, а не к сущностям. Объекты не создаются Spring, как это делают компоненты.