I am trying to write a map using com.amazonaws.services.dynamodb.datamodeling.DynamoDBMapper.save() and am getting this error:
Exception in thread "main"
com.amazonaws.services.dynamodb.datamodeling.DynamoDBMappingException:
Unsupported type: interface java.util.Map for public java.util.Map Config.getAttributes()
Is Map not supported by DynamoDBMapper?
Create a HashMapMarshaller
public class HashMapMarshaller extends JsonMarshaller<HashMap<String, String>>
{
#Override
public String marshall(HashMap<String, String> obj) {
return super.marshall(obj);
}
#Override
public HashMap<String, String> unmarshall(Class<HashMap<String, String>> clazz, String json) {
return super.unmarshall(clazz, json);
}
}
And then assign it to your property
#DynamoDBMarshalling(marshallerClass=HashMapMarshaller.class)
Related
I'd like to use a Kafka state store of type KeyValueStore in a sample application using the Kafka Binder of Spring Cloud Stream.
According to the documentation, it should be pretty simple.
This is my main class:
#SpringBootApplication
public class KafkaStreamTestApplication {
public static void main(String[] args) {
SpringApplication.run(KafkaStreamTestApplication.class, args);
}
#Bean
public BiFunction<KStream<String, String>, KeyValueStore<String,String>, KStream<String, String>> process(){
return (input,store) -> input.mapValues(v -> v.toUpperCase());
}
#Bean
public StoreBuilder myStore() {
return Stores.keyValueStoreBuilder(
Stores.persistentKeyValueStore("my-store"), Serdes.String(),
Serdes.String());
}
}
I suppose that the KeyValueStore should be passed as the second parameter of the "process" method, but the application fails to start with the message below:
Caused by: java.lang.IllegalStateException: No factory found for binding target type: org.apache.kafka.streams.state.KeyValueStore among registered factories: channelFactory,messageSourceFactory,kStreamBoundElementFactory,kTableBoundElementFactory,globalKTableBoundElementFactory
at org.springframework.cloud.stream.binding.AbstractBindableProxyFactory.getBindingTargetFactory(AbstractBindableProxyFactory.java:82) ~[spring-cloud-stream-3.0.3.RELEASE.jar:3.0.3.RELEASE]
at org.springframework.cloud.stream.binder.kafka.streams.function.KafkaStreamsBindableProxyFactory.bindInput(KafkaStreamsBindableProxyFactory.java:191) ~[spring-cloud-stream-binder-kafka-streams-3.0.3.RELEASE.jar:3.0.3.RELEASE]
at org.springframework.cloud.stream.binder.kafka.streams.function.KafkaStreamsBindableProxyFactory.afterPropertiesSet(KafkaStreamsBindableProxyFactory.java:103) ~[spring-cloud-stream-binder-kafka-streams-3.0.3.RELEASE.jar:3.0.3.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1855) ~[spring-beans-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1792) ~[spring-beans-5.2.5.RELEASE.jar:5.2.5.RELEASE]
I found the solution about how to use a store reading an unit test in Spring Cloud Stream.
The code below is how I applied that solution to my code.
The transformer uses the Store provided by Spring bean method "myStore"
#SpringBootApplication
public class KafkaStreamTestApplication {
public static final String MY_STORE_NAME = "my-store";
public static void main(String[] args) {
SpringApplication.run(KafkaStreamTestApplication.class, args);
}
#Bean
public Function<KStream<String, String>, KStream<String, String>> process2(){
return (input) -> input.
transformValues(() -> new MyValueTransformer(), MY_STORE_NAME);
}
#Bean
public StoreBuilder<?> myStore() {
return Stores.keyValueStoreBuilder(
Stores.persistentKeyValueStore(MY_STORE_NAME), Serdes.String(),
Serdes.String());
}
}
public class MyValueTransformer implements ValueTransformer<String, String> {
private KeyValueStore<String,String> store;
private ProcessorContext context;
#Override
public void init(ProcessorContext context) {
this.context = context;
store = (KeyValueStore<String, String>) this.context.getStateStore(KafkaStreamTestApplication.MY_STORE_NAME);
}
#Override
public String transform(String value) {
String tValue = store.get(value);
if(tValue==null) {
store.put(value, value.toUpperCase());
}
return tValue;
}
#Override
public void close() {
if(store!=null) {
store.close();
}
}
}
I am trying to convert / serialize the #Id field (which is not a string) of the model class but keep getting this error. The custom ID class just concatenates two values with a colon, e.g. aaaa:2345.
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [MyIdClass] to type [byte[]]
This is my model class.
#RedisHash("alert")
public class MyClass implements Serializable
{
public static class MyIdClass
{
public String userId;
public Long sessionExpiry;
public MyIdClass()
{
}
public MyIdClass(String id, Long ex)
{
userId = id;
sessionExpiry = ex;
}
}
public static class MyIdClassSerializer implements RedisSerializer<MyIdClass>
{
#Nullable
#Override
public byte[] serialize(#Nullable MyIdClass uid) throws SerializationException
{
return String.format("%s:%d", uid.userId, uid.sessionExpiry).getBytes();
}
#Nullable
#Override
public MyIdClass deserialize(#Nullable byte[] bytes) throws SerializationException
{
String[] t = new String(bytes).split(":");
return new MyIdClass(t[0], Long.parseLong(t[1]));
}
}
#Component
#ReadingConverter
public static class MyIdClassReader implements Converter<byte[], MyIdClass>
{
#Nullable
#Override
public MyIdClass convert(byte[] source)
{
String[] t = new String(source).split(":");
return new MyIdClass(t[0], Long.parseLong(t[1]));
}
}
#Component
#WritingConverter
public static class MyIdClassWriter implements Converter<MyIdClass, byte[]>
{
#Nullable
#Override
public byte[] convert(MyIdClass uid)
{
return String.format("%s:%d", uid.userId, uid.sessionExpiry).getBytes();
}
}
/**
* User ID
* Key := 'alert:' userId ':' sessionExpiry
*/
#Id
public MyIdClass id;
public String value;
}
Here's how I'm configuring the RedisTemplate.
#Bean("redisTemplateActivityAlert")
public RedisTemplate<ActivityAlert.UserIdExpiry, ActivityAlert> redisTemplateActivityAlert()
{
RedisTemplate<ActivityAlert.UserIdExpiry, ActivityAlert> template = new RedisTemplate<>();
template.setConnectionFactory(jedisConnectionFactory());
template.setKeySerializer(new ActivityAlert.UserIdExpirySerializer());
template.setHashKeySerializer(new ActivityAlert.UserIdExpirySerializer());
return template;
}
I've read other posts about configuring ConversionService or TypeConverter but haven't gone far with them.
add this Bean to your RedisConfiguration :
#Bean
public RedisCustomConversions redisCustomConversions(MyIdClassReader myIdClassReader , MyIdClassWriter myIdClassWriter ) {
return new RedisCustomConversions(Arrays.asList(myIdClassWriter,myIdClassReader));
}
Error log:
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'converter' defined in class path resource
[...../spring/controller/PsvJackson2HttpMessageConverter.class]:
No matching factory method found: factory bean 'psvJackson2HttpMessageConverter';
factory method 'converter()'.
Check that a method with the specified name exists and that it is non-static.
And here is the configuration class:
#Configuration
public class PsvJackson2HttpMessageConverter extends WebMvcConfigurationSupport {
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(converter());
converters.add(new ByteArrayHttpMessageConverter());
converters.add(new StringHttpMessageConverter());
super.addDefaultHttpMessageConverters(converters);
}
#Bean
MappingJackson2HttpMessageConverter converter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
converter.setObjectMapper(objectMapper);
return converter;
}
}
Don't know what is wrong here.
Here is the thing which you can do:
Create a configuration class, which registers/maps the converters.
Create custom converter class.
For example, here is the config class:
#EnableWebMvc
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void configureMessageConverters(final List<HttpMessageConverter<?>> converters) {
converters.add(new CustomMappingJackson2HttpMessageConverter());
super.configureMessageConverters(converters);
}
}
and here is the converter class:
public class CustomMappingConverter extends AbstractJackson2HttpMessageConverter {
public CustomMappingConverter(final ObjectMapper objectMapper){
super(objectMapper, MediaType.APPLICATION_JSON, new MediaType("application", "*+json"), new MediaType("application", "jsonp"));
}
private String jsonPrefix;
public CustomMappingConverter() {
this(Jackson2ObjectMapperBuilder.json().build());
}
public void setJsonPrefix(final String jsonPrefix) {
this.jsonPrefix = jsonPrefix;
}
public void setPrefixJson(final boolean prefixJson) {
jsonPrefix = prefixJson ? ")]}', " : null;
}
#Override
protected void writePrefix(final JsonGenerator generator, final Object object) throws IOException {
if (jsonPrefix != null) {
generator.writeRaw(jsonPrefix);
}
final String jsonpFunction =
object instanceof MappingJacksonValue ? ((MappingJacksonValue) object).getJsonpFunction() : null;
if (jsonpFunction != null) {
generator.writeRaw("/**/");
generator.writeRaw(jsonpFunction + "(");
}
}
#Override
protected void writeSuffix(final JsonGenerator generator, final Object object) throws IOException {
final String jsonpFunction =
object instanceof MappingJacksonValue ? ((MappingJacksonValue) object).getJsonpFunction() : null;
if (jsonpFunction != null) {
generator.writeRaw(");");
}
}
}
I tried to populate a tableView, I followed the tutorial given in docs.oracle, but in my table there are Integer fields, so I do the same thing to add them.
The code in the information class (like Person class):
private SimpleIntegerProperty gel;
public int getGel() {
return gel.get();
}
public void setGel(int pop) {
gel.set(pop);
}
The code in the Main class:
TableColumn gel = new TableColumn("Gel");
gel.setMinWidth(100);
gel.setCellValueFactory(new PropertyValueFactory<Information, Integer>("gel"));
gel.setCellFactory(TextFieldTableCell.forTableColumn());
gel.setOnEditCommit(new EventHandler<CellEditEvent<Information, Integer>>() {
#Override
public void handle(CellEditEvent<Information, Integer> t) {
((Information) t.getTableView().getItems()
.get(t.getTablePosition().getRow()))
.setGel(t.getNewValue());
}
});
but I have errors:
Caused by: java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at javafx.util.converter.DefaultStringConverter.toString(DefaultStringConverter.java:34)
at javafx.scene.control.cell.CellUtils.getItemText(CellUtils.java:100)
at javafx.scene.control.cell.CellUtils.updateItem(CellUtils.java:201)
at javafx.scene.control.cell.TextFieldTableCell.updateItem(TextFieldTableCell.java:204)
The problem is in your cell factory.
TableColumn should be typed to TableColumn<Information, Integer>. Then you will see an error here:
gel.setCellFactory(TextFieldTableCell.forTableColumn());
(the same error you have on runtime). The reason is the static callback forTableColumn is only for TableColumnof type String.
For other types you have to provide a custom string converter. This will solve your problems:
gel.setCellFactory(TextFieldTableCell.forTableColumn(new StringConverter<Integer>(){
#Override
public String toString(Integer object) {
return object.toString();
}
#Override
public Integer fromString(String string) {
return Integer.parseInt(string);
}
}));
I create form and controller this form have some validation constrains using Hibernate validator. I face problem when starting test the validation constrains but I got Blue Exception page with the attributemodel with the rejected.
This the configuration
#Configuration
#ComponentScan(basePackages = {"com.whatever.core.web"})
#EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurationSupport {
private static final String MESSAGE_SOURCE = "/WEB-INF/classes/messages";
private static final String TILES = "/WEB-INF/tiles/tiles.xml";
private static final String VIEWS = "/WEB-INF/views/**/views.xml";
private static final String RESOURCES_HANDLER = "/resources/";
private static final String RESOURCES_LOCATION = RESOURCES_HANDLER + "**";
#Override
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping requestMappingHandlerMapping = super.requestMappingHandlerMapping();
requestMappingHandlerMapping.setUseSuffixPatternMatch(false);
requestMappingHandlerMapping.setUseTrailingSlashMatch(false);
return requestMappingHandlerMapping;
}
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new MappingJacksonHttpMessageConverter());
}
#Bean(name = "messageSource")
public MessageSource configureMessageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename(MESSAGE_SOURCE);
messageSource.setCacheSeconds(5);
return messageSource;
}
#Bean
public TilesViewResolver configureTilesViewResolver() {
return new TilesViewResolver();
}
#Bean
public TilesConfigurer configureTilesConfigurer() {
TilesConfigurer configurer = new TilesConfigurer();
configurer.setDefinitions(new String[] {TILES, VIEWS});
return configurer;
}
#Override
public Validator getValidator() {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.setValidationMessageSource(configureMessageSource());
return validator;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler(RESOURCES_HANDLER).addResourceLocations(RESOURCES_LOCATION);
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
and the controller here
if(result.hasErrors()){
return null; OR "view name"
}
User user = new User();
user.setUsername(userModel.getUsername());
user.setFirstName(userModel.getFirstName());
user.setLastName(userModel.getLastName());
user.setGender(userModel.getGender());
user.setLocation(userModel.getLocation());
user.setPassword(passwordEncoder.encodePassword(userModel.getPassword(),null));
userRepository.save(user);
doAutoLogin(userModel.getUsername(),userModel.getPassword(),request);
return "redirect:/home";
NOTE: I use springMVC, spring security, tiles, and hibernate validator
I used SpringMVC with hibernate validator with XML configuration and portal environment and work fine I don't know what the wrong here!!
I Found the issue! the signature of the method controller should be like this
public String signup(#ModelAttribute("userModel") #Valid SignupForm userModel,BindingResult result,HttpServletRequest request,HttpServletResponse response,ModelMap model)
as what I read in sprinsource forum, the BindingResult should follow the modelAttribute and work find. I didn't find any official documentation for this but its work now.
to see the thread of springsource forum check this link http://forum.springsource.org/showthread.php?85815-BindException-Thrown-on-bind-errors-(instead-of-returning-errors-to-controller-method