Spring @ConfigurationProperties экземпляр в JSON с Джексоном: не найден сериализатор - PullRequest
0 голосов
/ 08 апреля 2019

У меня следующий код:

@Data
@Validated
@ConfigurationProperties
public class Keys {

    private final Key key = new Key();

    @Data
    @Validated
    @ConfigurationProperties(prefix = "key")
    public class Key {

        private final Client        client          = new Client();
        private final IntentToken   intentToken     = new IntentToken();
        private final Intent        intent          = new Intent();
        private final OAuth         oauth           = new OAuth();
        private final ResourceToken resourceToken   = new ResourceToken();

        @Valid @NotNull private String authorization;
        @Valid @NotNull private String bearer;
    ...
    }
}

Это экземпляр, представляющий файл свойств, например:

key.authorization=Authorization
key.bearer=Bearer
..

Поскольку у меня могут быть разные источники для свойств (файл свойств, MongoDB и т. д.) У меня есть клиент, который наследуется от ключей следующим образом:

Источник файлов свойств

@Component
@Configuration
@Primary
@PropertySource("classpath:${product}-keys.${env}.properties")
//@JsonAutoDetect(fieldVisibility = Visibility.ANY)
public class CustomerKeysProperties extends Keys {

}

Источник монго

@Data
@EqualsAndHashCode(callSuper=true)
@Component
//@Primary
@Document(collection = "customerKeys")
public class CustomerKeysMongo extends Keys {
    @Id
    private String id;
}

Я просто выбираю источник, который хочу использовать, аннотируя класс с помощью @Primary.В приведенном выше примере CustomerKeysProperties является активным источником.

Все это отлично работает.У меня возникает проблема, когда я пытаюсь преобразовать экземпляр CustomerKeysProperties в JSON, как показано в следующем коде:

@SpringBootApplication
public class ConverterUtil {

    public static void main(String[] args) throws Exception {
        SpringApplication.run(ConverterUtil.class, args);
    }

    @Component
    class CustomerInitializer implements CommandLineRunner {

        @Autowired 
        private Keys k;
        private final ObjectMapper mapper = new ObjectMapper();

        @Override
        public void run(String... args) throws Exception {
            mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
            //mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
            String jsonInString = mapper.writeValueAsString(k);
            System.out.println(jsonInString);
        }
    }
}

Хотя k содержит все установленные свойства, преобразование завершается неудачно:

Caused by:     com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: x.client.customer.properties.CustomerKeysProperties$$EnhancerBySpringCGLIB$$eda308bd["CGLIB$CALLBACK_0"]->org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor["advised"]->org.springframework.aop.framework.ProxyFactory["targetSource"]->org.springframework.aop.target.SingletonTargetSource["target"]->x.client.customer.properties.CustomerKeysProperties$$EnhancerBySpringCGLIB$$4fd6c568["CGLIB$CALLBACK_0"])
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77)
at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1191)

И если я раскомментирую mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false), как предложено в журналах, у меня в Джексоне будет бесконечный цикл, вызывающий переполнение стека:

at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:727)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:119)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:79)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:18)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:727)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
..

Вопросы

В конце я просто хочу предоставить класс Util, который может конвертировать файл свойств в формате JSON, который будет храниться в MongoDB.

  1. Как я могу решить эту проблему?
  2. Не проходя через описанный выше объект, как я могу преобразовать файл свойств в JSON?
  3. Можно ли сохранить произвольный компонент Java в MongoDB с автоматическим преобразованием в JSON?

Было бы полезно ответить на любой из 3 приведенных выше вопросов.

Примечания

  • Следует отметить, что я использую ломбок.Не уверен, что это проблема.
  • Другое предположение, что я пытаюсь сериализовать управляемый bean-компонент Spring, и задействованный им прокси-сервер приводит к тому, что Джексон не может выполнять сериализацию?Если да, то что может быть поворотом?

Спасибо!

1 Ответ

0 голосов
/ 08 апреля 2019

Итак, нашли проблему:

Джексон не может обработать управляемый бин.

Поворот был

            try (InputStream input = getClass().getClassLoader().getResourceAsStream("foo.properties")) {
                JavaPropsMapper mapper = new JavaPropsMapper();
                Keys keys = mapper.readValue(input, Keys.class);
                ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
                String res = ow.writeValueAsString(keys);
                System.out.println(res);
            } catch (IOException e) {
                e.printStackTrace();
            }

, где Keys - управляемый компонент Spring, который я вводил.

И

JavaPropsMapper от:

    <dependency>
        <groupId>com.fasterxml.jackson.dataformat</groupId>
        <artifactId>jackson-dataformat-properties</artifactId>
    </dependency>
...