#json #mongodb #spring-boot #java-8 #jackson
#json #mongodb #весенняя загрузка #java-8 #джексон
Вопрос:
У меня следующий код:
@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 {
}
Исходный код Mongo
@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);
}
}
}
While k
contains all the properties set, the conversion fails:
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)
как указано в журналах, у меня в Jackson происходит бесконечный цикл, вызывающий stackoverflow:
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.
- Как я могу решить эту проблему?
- Как я могу преобразовать файл свойств в JSON без прохождения через объект выше?
- Могу ли я сохранить произвольный Java-компонент в MongoDB с автоматическим преобразованием в JSON?
Ответ на любой из 3 вопросов выше был бы полезен.
Примечания
- Следует отметить, что я использую lombok. Не уверен, что это проблема.
- Другое предположение заключается в том, что я пытаюсь сериализовать компонент, управляемый Spring, и прокси, который он использует, приводит к тому, что Джексон не может выполнить сериализацию? Если да, то каким может быть поворот?
Спасибо!
Ответ №1:
Итак, найдена проблема:
джексон не может обработать управляемый компонент.
Поворот был
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>