如何在Spring Data Rest应用程序中注册Converter

时间:2018-02-22 15:32:31

标签: spring spring-data-rest

我有Spring转换器,它使用Spring Data REST的组件EnumTranslator

@Component
public class TranslationStringToSpecificationStatusEnumConverter implements Converter<String, Specification.Status> {

    private final EnumTranslator enumTranslator;

    @Autowired
    public TranslationStringToSpecificationStatusEnumConverter(EnumTranslator enumTranslator) {
        this.enumTranslator = enumTranslator;
    }

    @Override
    public Specification.Status convert(String source) {
        return enumTranslator.fromText(Specification.Status.class, source);
    }
}

注册此转换器的推荐方法是子类RepositoryRestConfigurerAdapter,如下所示:

@Configuration
public class RepositoryRestConfig extends RepositoryRestConfigurerAdapter {

    private final TranslationStringToSpecificationStatusEnumConverter converter;

    @Autowired
    public RepositoryRestConfig(TranslationStringToSpecificationStatusEnumConverter converter) {
        this.converter = converter;
    }

    @Override
    public void configureConversionService(ConfigurableConversionService conversionService) {
        conversionService.addConverter(converter);
        super.configureConversionService(conversionService);
    }
}

当我运行Spring Boot应用程序时,它在以下方面失败:

***************************
APPLICATION FAILED TO START
***************************

Description:

The dependencies of some of the beans in the application context form a cycle:
┌─────┐
|  translationStringToSpecificationStatusEnumConverter defined in file ...
↑     ↓
|  org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration (field java.util.List org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration.configurers)
↑     ↓
|  repositoryRestConfig defined in file ...
└─────┘

所以存在循环bean依赖。

如何在上面注册转换器,以便我不会引入循环bean依赖?

2 个答案:

答案 0 :(得分:1)

使其有效:

@Override
public void configureConversionService(ConfigurableConversionService conversionService) {
   conversionService.addConverter(String.class, Status.class, new StringToTranslatedEnumConverter<>(Status.class));
   super.configureConversionService(conversionService);
}       

首先,我创建了实用程序类,帮助我在非托管对象中使用Spring bean:

@Component
public final class SpringUtils {

    @Autowired private ApplicationContext ctx;

    private static SpringUtils instance;

    @PostConstruct
    private void registerInstance() {
        instance = this;
    }

    public static <T> T getBean(Class<T> clazz) {
        return instance.ctx.getBean(clazz);
    }
}

然后我创建了转换器:

public class StringToTranslatedEnumConverter<T extends Enum<T> & TranslatedEnum> implements Converter<String, T> {

    private final ConcurrentMapCache cache;
    private EnumTranslator enumTranslator;

    private Class<T> type;

    public StringToTranslatedEnumConverter(Class<T> type) {
        this.type = type;
        cache = new ConcurrentMapCache(type.getName());
    }

    @Override
    public T convert(String from) {

        if (enumTranslator == null) {
            enumTranslator = SpringUtils.getBean(EnumTranslator.class);
        }

        Cache.ValueWrapper wrapper = cache.get(from);
        if (wrapper != null) {
            //noinspection unchecked
            return (T) wrapper.get();
        }

        T translatedEnum = enumTranslator.fromText(type, from);
        cache.put(from, translatedEnum);
        return translatedEnum;
    }
}

<强>已更新

TranslatedEnum - 它的界面标记,用于标记只需要翻译的枚举。

public interface TranslatedEnum {
}

public enum Status implements TranslatedEnum {
    CREATED, DELETED
}

答案 1 :(得分:1)

此问题的解决方案是Spring Core特定的。为了打破循环bean依赖循环,我们必须在RepositoryRestConfig中延迟设置转换器。它可以通过二传手注射来实现:

@Component
public class RepositoryRestConfig extends RepositoryRestConfigurerAdapter {

    private TranslationStringToSpecificationStatusEnumConverter converter;

    @Override
    public void configureConversionService(ConfigurableConversionService conversionService) {
        conversionService.addConverter(converter);
        super.configureConversionService(conversionService);
    }

    @Autowired
    public void setConverter(TranslationStringToSpecificationStatusEnumConverter converter) {
        this.converter = converter;
    }
}

你可以在Greg Turnquist的提交中找到解决方法:https://github.com/pmihalcin/custom-converter-in-spring-data-rest/commit/779a6477d76dc77515b3e923079e5a6543242da2