如何为Spring Data Cassandra创建自定义转换?

huangapple go评论67阅读模式
英文:

How to create custom conversions for Spring Data Cassandra?

问题

I'm not able to create custom conversions in order to use Currency and Locale as data types.

I'm using a @Configuration annotated class which will be auto-configured with META-INF/spring.factories:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.acme.autoconfigure.ConverterAutoConfiguration

I tried registering the converters directly as beans and also tried to create CassandraCustomConversions bean without success:

@Configuration
public class ConverterAutoConfiguration {
	/*
	@Bean
	public Converter<String, Currency> currencyReadConverter() {
		// ...
	}

	@Bean
	public Converter<Currency, String> currencyWriteConverter() {
		// ...
	}

	@Bean
	public Converter<String, Locale> localeReadConverter() {
		// ...
	}

	@Bean
	public Converter<Locale, String> localeWriteConverter() {
		// ...
	}
	*/

	@Bean
	public CassandraCustomConversions cassandraCustomConversions() {
		// ...
	}

	enum CurrencyReadConverter implements Converter<String, Currency> {
		// ...
	}

	enum CurrencyWriteConverter implements Converter<Currency, String> {
		// ...
	}

	enum LocaleReadConverter implements Converter<String, Locale> {
		// ...
	}

	enum LocaleWriteConverter implements Converter<Locale, String> {
		// ...
	}
}

With the CassandraCustomConversions bean I'm getting an exception directly at startup:

Caused by: org.springframework.data.mapping.MappingException: Cannot resolve DataType for type [class java.lang.String] for property [categoryId] in entity [com.acme.model.Category]; Consider registering a Converter or annotating the property with @CassandraType.

It seems it's losing all the default mappings.

When using the converter beans directly I'm getting the following exception:

org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract reactor.core.publisher.Flux com.acme.repository.CategoryLocaleReactiveRepository.findByUriNameInAndKeyLocale(java.util.Collection,java.util.Locale)! Reason: Could not inline literal of type java.util.Locale. This happens because the driver doesn't know how to map it to a CQL type. Try passing a TypeCodec or CodecRegistry to literal().

Based on this issue this should be possible somehow: link to GitHub issue

英文:

I'm not able to create custom conversions in order to use Currency and Locale as data types.

I'm using a @Configuration annotated class which will be auto-configured with META-INF/spring.factories:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.acme.autoconfigure.ConverterAutoConfiguration

I tried registering the converters directly as beans and also tried to create CassandraCustomConversions bean without success:

@Configuration
public class ConverterAutoConfiguration {
	/*
	@Bean
	public Converter&lt;String, Currency&gt; currencyReadConverter() {
		return new Converter&lt;String, Currency&gt;() {
			@Override
			public Currency convert(String source) {
				return Currency.getInstance(source);
			}
		};
	}

	@Bean
	public Converter&lt;Currency, String&gt; currencyWriteConverter() {
		return new Converter&lt;Currency, String&gt;() {
			@Override
			public String convert(Currency source) {
				return source.toString();
			}
		};
	}

	@Bean
	public Converter&lt;String, Locale&gt; localeReadConverter() {
		return new Converter&lt;String, Locale&gt;() {
			@Override
			public Locale convert(String source) {
				return StringUtils.parseLocaleString(source);
			}
		};
	}

	@Bean
	public Converter&lt;Locale, String&gt; localeWriteConverter() {
		return new Converter&lt;Locale, String&gt;() {
			@Override
			public String convert(Locale source) {
				return source.toString();
			}
		};
	}
	*/

	@Bean
	public CassandraCustomConversions cassandraCustomConversions() {
		List&lt;Converter&lt;?, ?&gt;&gt; converters = new ArrayList&lt;&gt;();
		converters.add(CurrencyReadConverter.INSTANCE);
		converters.add(CurrencyWriteConverter.INSTANCE);
		converters.add(LocaleReadConverter.INSTANCE);
		converters.add(LocaleWriteConverter.INSTANCE);

		return new CassandraCustomConversions(converters);
	}

	enum CurrencyReadConverter implements Converter&lt;String, Currency&gt; {
		INSTANCE;

		@Override
		public Currency convert(String source) {
			return Currency.getInstance(source);
		}
	}

	enum CurrencyWriteConverter implements Converter&lt;Currency, String&gt; {
		INSTANCE;

		@Override
		public String convert(Currency source) {
			return source.toString();
		}
	}

	enum LocaleReadConverter implements Converter&lt;String, Locale&gt; {
		INSTANCE;

		@Override
		public Locale convert(String source) {
			return StringUtils.parseLocaleString(source);
		}
	}

	enum LocaleWriteConverter implements Converter&lt;Locale, String&gt; {
		INSTANCE;

		@Override
		public String convert(Locale source) {
			return source.toString();
		}
	}
}

With the CassandraCustomConversions bean I'm getting an exception directly at startup:

Caused by: org.springframework.data.mapping.MappingException: Cannot resolve DataType for type [class java.lang.String] for property [categoryId] in entity [com.acme.model.Category]; Consider registering a Converter or annotating the property with @CassandraType.

It seems its loosing all the default mappings.

When using the converter beans directly I'm getting the following exception:

org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract reactor.core.publisher.Flux com.acme.repository.CategoryLocaleReactiveRepository.findByUriNameInAndKeyLocale(java.util.Collection,java.util.Locale)! Reason: Could not inline literal of type java.util.Locale. This happens because the driver doesn&#39;t know how to map it to a CQL type. Try passing a TypeCodec or CodecRegistry to literal().

Based on this issue this should be possible somehow: https://github.com/spring-projects/spring-boot/issues/8411

答案1

得分: 3

尝试将@WritingConverter@ReadingConverter添加到您的转换器中。我相信Spring在决定使用哪个转换器与非自定义类型一起使用时会有些困难。

一旦将这两个注释添加到适当的转换器中,我创建了一个本地项目,并成功实现了LocaleCurrency的转换。

如果您仍然遇到问题,我可以将我的测试项目推送到Github并分享给您。

参考链接:https://docs.spring.io/spring-data/cassandra/docs/current/reference/html/#customconversions.java

示例项目:https://github.com/michaelmcfadyen/spring-data-cassandra-custom-converter-example

英文:

Try adding @WritingConverter and @ReadingConverter to your converters. I believe spring struggles a bit in deciding which converter to use with non custom types.

I created a local project and managed to get the conversion of Locale and Currency working once those 2 annotations were added to the appropriate converter.

I can push my test project to Github and share if you are still having issues.

Reference: https://docs.spring.io/spring-data/cassandra/docs/current/reference/html/#customconversions.java

Example Project: https://github.com/michaelmcfadyen/spring-data-cassandra-custom-converter-example

huangapple
  • 本文由 发表于 2020年8月13日 00:10:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/63380561.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定