Sprinboot Jackson Date Serialize - spring-boot

i face a litle problem with Jackson on springboot web, i'm expecting this kind of response.
{
'date': 'string of date'
}
but i get back this
[
0: java.sql.date,
1: long number of timestamp
]
please how to configure springboot to avoid this?
#Configuration
public class BootConfiguration {
#Bean
#Primary
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
#Bean
public JavaTimeModule javaTimeModule() {
return new JavaTimeModule();
}
#Bean
public Jdk8Module jdk8TimeModule() {
return new Jdk8Module();
}
#Bean
public CoreJackson2Module coreJackson2Module() {
return new CoreJackson2Module();
}
#Bean
public OAuth2AuthorizationServerJackson2Module authorizationServerJackson2Module(){
return new OAuth2AuthorizationServerJackson2Module();
}
public List<Module> securityModules(){
ClassLoader classLoader = JdbcOAuth2AuthorizationService.class.getClassLoader();
return SecurityJackson2Modules.getModules(classLoader);
}
#Bean
#Primary
#Order(Ordered.HIGHEST_PRECEDENCE)
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper().findAndRegisterModules();
mapper.registerModule(coreJackson2Module());
mapper.registerModule(javaTimeModule());
mapper.registerModule(jdk8TimeModule());
mapper.registerModules(securityModules());
mapper.registerModule(authorizationServerJackson2Module());
mapper.addMixIn(UserPrincipal.class, Object.class);
return mapper;
}
}
this is the controller method where
#GetMapping(value = "/authentications", params = {"pge","lmt", "slug"})
public ResponseEntity<?> getLastLogins(
Authentication authentication,
#RequestParam("lmt")Integer limit,
#RequestParam("pge")Integer page,
#RequestParam("slug")String slug){
return new ResponseEntity<>(loginManager.findAllAuthentications(authentication.getName(),slug,limit,page), HttpStatus.OK);
}
}
and this is the model containing the properties i try to get back
#Data
public class User implements Serializable {
private String firstName;
private String lastName;
private Date date;
private Role role;
}

Related

How to use error-channel for catching exception in Spring Integration?

What I am trying to do? : I am new to Spring Integration and already have read many similar questions regarding error handling but I don't understand how to catch exceptions using error-channel?
What I have done so far:
#EnableIntegration
#IntegrationComponentScan
#Configuration
public class TcpClientConfig implements ApplicationEventPublisherAware {
private ApplicationEventPublisher applicationEventPublisher;
private final ConnectionProperty connectionProperty;
#Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
TcpClientConfig(ConnectionProperty connectionProperty) {
this.connectionProperty = connectionProperty;
}
#Bean
public AbstractClientConnectionFactory clientConnectionFactory() {
TcpNioClientConnectionFactory tcpNioClientConnectionFactory =
getTcpNioClientConnectionFactoryOf(
connectionProperty.getPrimaryHSMServerIpAddress(),
connectionProperty.getPrimaryHSMServerPort());
final List<AbstractClientConnectionFactory> fallBackConnections = getFallBackConnections();
fallBackConnections.add(tcpNioClientConnectionFactory);
final FailoverClientConnectionFactory failoverClientConnectionFactory =
new FailoverClientConnectionFactory(fallBackConnections);
return new CachingClientConnectionFactory(
failoverClientConnectionFactory, connectionProperty.getConnectionPoolSize());
}
#Bean
DefaultTcpNioSSLConnectionSupport connectionSupport() {
final DefaultTcpSSLContextSupport defaultTcpSSLContextSupport =
new DefaultTcpSSLContextSupport(
connectionProperty.getKeystorePath(),
connectionProperty.getTrustStorePath(),
connectionProperty.getKeystorePassword(),
connectionProperty.getTruststorePassword());
final String protocol = "TLSv1.2";
defaultTcpSSLContextSupport.setProtocol(protocol);
return new DefaultTcpNioSSLConnectionSupport(defaultTcpSSLContextSupport, false);
}
#Bean
public MessageChannel outboundChannel() {
return new DirectChannel();
}
#Bean
#ServiceActivator(inputChannel = "outboundChannel")
public MessageHandler outboundGateway(AbstractClientConnectionFactory clientConnectionFactory) {
TcpOutboundGateway tcpOutboundGateway = new TcpOutboundGateway();
tcpOutboundGateway.setConnectionFactory(clientConnectionFactory);
return tcpOutboundGateway;
}
#Bean
#ServiceActivator(inputChannel = "error-channel")
public void handleError(ErrorMessage em) {
throw new RuntimeException(String.valueOf(em));
}
private List<AbstractClientConnectionFactory> getFallBackConnections() {
final int size = connectionProperty.getAdditionalHSMServersConfig().size();
List<AbstractClientConnectionFactory> collector = new ArrayList<>(size);
for (final Map.Entry<String, Integer> server :
connectionProperty.getAdditionalHSMServersConfig().entrySet()) {
collector.add(getTcpNioClientConnectionFactoryOf(server.getKey(), server.getValue()));
}
return collector;
}
private TcpNioClientConnectionFactory getTcpNioClientConnectionFactoryOf(
final String ipAddress, final int port) {
TcpNioClientConnectionFactory tcpNioClientConnectionFactory =
new TcpNioClientConnectionFactory(ipAddress, port);
tcpNioClientConnectionFactory.setUsingDirectBuffers(true);
tcpNioClientConnectionFactory.setDeserializer(new CustomDeserializer());
tcpNioClientConnectionFactory.setApplicationEventPublisher(applicationEventPublisher);
tcpNioClientConnectionFactory.setSoKeepAlive(true);
tcpNioClientConnectionFactory.setConnectTimeout(connectionProperty.getConnectionTimeout());
tcpNioClientConnectionFactory.setSoTcpNoDelay(true);
tcpNioClientConnectionFactory.setTcpNioConnectionSupport(connectionSupport());
return tcpNioClientConnectionFactory;
}
}
Gateway
#Component
#MessagingGateway(defaultRequestChannel = "outboundChannel",errorChannel ="error-channel" )
public interface TcpClientGateway {
String send(String message);
}
Also currently, I am facing
required a bean of type org.springframework.messaging.support.ErrorMessage that could not be found
I need some assistance!
Thanking you in advance,
EDIT
#AllArgsConstructor
#Service
public class AsyncNonBlockingClient implements Connector {
TcpClientGateway tcpClientGateway;
#Override
public String send(final String payload) {
return tcpClientGateway.send(payload);
}
}
See documentation about messaging annotation:
Your problem is here: https://docs.spring.io/spring-integration/docs/current/reference/html/configuration.html#annotations_on_beans
#Bean
#ServiceActivator(inputChannel = "error-channel")
public void handleError(ErrorMessage em) {
This is a plain POJO method, therefore it cannot be marked with a #Bean. You use a #Bean really for beans to expose. Then you decide if that has to be a #ServiceActivator or not. So, just remove #Bean from this method and your error-channel consumer should be OK.

How to connect Redis and Couchbase in spring

How can I connect redis and couchbase to my spring application.
I get this error Parameter 0 of method couchbaseMappingContext in org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration required a single bean, but 2 were found: - couchbaseCustomConversions: defined by method 'customConversions' in class path resource [{classPath}/chat/config/CouchbaseConfiguration.class] - redisCustomConversions: defined in null
I only need redis to 'look' at one package and the other ones need to be connected with only couchbase.
Redis config
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
MappingJackson2HttpMessageConverter converter =
new MappingJackson2HttpMessageConverter(mapper);
return converter;
}
#Bean
public RedisTemplate<Long, ?> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<Long, ?> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
// Add some specific configuration here. Key serializers, etc.
return template;
}
Couchbase config
#EnableCouchbaseRepositories
#Configuration
public class CouchbaseConfiguration extends AbstractCouchbaseConfiguration {
#Value("${spring.data.couchbase.bucket-name}")
private String bucketName;
#Value("${spring.couchbase.username}")
private String username;
#Value("${spring.couchbase.password}")
private String password;
#Value("${spring.couchbase.connection-string}")
private String connectionString;
#Override
public String getConnectionString() {
return this.connectionString;
}
#Override
public String getUserName() {
return this.username;
}
#Override
public String getPassword() {
return this.password;
}
#Override
public String getBucketName() {
return this.bucketName;
}
}
and when I first start my app in terminal there is this info : Spring Data Redis - Could not safely identify store assignment for repository candidate interface
To resolve the ambiguity in taking the customConversions bean, we could tell the couchbase configuration class how to create the customConversions bean. Adding the below code to the class which extends AbstractCouchbaseConfiguration should solve the issue
#Bean
public CustomConversions customConversions() {
return super.customConversions();
}

How can we take the result of `MethodInvokingTaskletAdapter` as a reader in the Spring Batch Step?

How can we take the result of MethodInvokingTaskletAdapter as a reader in the Spring Batch Step? Reference - https://docs.spring.io/spring-batch/docs/current/reference/html/index-single.html#taskletStep and https://github.com/spring-projects/spring-batch/pull/567
Here is the code that I developed
JobConfiguration.java
#Configuration
public class JobConfiguration {
#Autowired
private JobBuilderFactory jobBuilderFactory;
#Autowired
private StepBuilderFactory stepBuilderFactory;
#Bean
public CustomService service() {
return new CustomService();
}
#StepScope
#Bean
public MethodInvokingTaskletAdapter methodInvokingTasklet() {
MethodInvokingTaskletAdapter methodInvokingTaskletAdapter = new MethodInvokingTaskletAdapter();
methodInvokingTaskletAdapter.setTargetObject(service());
methodInvokingTaskletAdapter.setTargetMethod("getEmployees");
return methodInvokingTaskletAdapter;
}
#Bean
public Job methodInvokingJob() {
return this.jobBuilderFactory.get("methodInvokingJob")
.start(methodInvokingStep())
.build();
}
#Bean
public Step methodInvokingStep() {
// Looking to configure the Chunk based Step here, dont know how to do using MethodInvokingTaskletAdapter
return this.stepBuilderFactory.get("methodInvokingStep")
.tasklet(methodInvokingTasklet())
.build();
}
}
CustomService.java
public class CustomService {
public void serviceMethod(String message) {
System.out.println(message);
}
public void invokeMethod() {
System.out.println("=============== Your method has executed !");
}
public List<Employee> getEmployees(){
// In real world, it will be an GET API call to XYZ system
List<Employee> employees = new ArrayList<>();
employees.add(Employee.builder().firstName("Ravi").lastName("Shankar").email("ravi.shankar#gmail.com").age(30).build());
employees.add(Employee.builder().firstName("Parag").lastName("Rane").email("parag.rane#gmail.com").age(11).build());
employees.add(Employee.builder().firstName("Priya").lastName("Pande").email("priya.pande#gmail.com").age(40).build());
employees.add(Employee.builder().firstName("Kiran").lastName("khot").email("kiran.khot#gmail.com").age(50).build());
return employees;
}
}
Employee.java
#Data
#AllArgsConstructor
#NoArgsConstructor
#Builder
public class Employee {
private String firstName;
private String lastName;
private String email;
private int age;
}
MethodInvokingTaskletApplication.java
#EnableBatchProcessing
#SpringBootApplication
public class MethodInvokingTaskletApplication {
public static void main(String[] args) {
SpringApplication.run(MethodInvokingTaskletApplication.class, args);
}
}
To answer your question, you can't. The MethodInvokingTaskletAdapter is meant to adapt a POJO to a Tasklet. We have an ItemReaderAdapter that you can use to adapt a POJO to an ItemReader. You can read about it in the documentation here: https://docs.spring.io/spring-batch/docs/current/api/org/springframework/batch/item/adapter/ItemReaderAdapter.html
Now you'll have an issue with your service as configured in that each call to the delegating POJO is considered an item. That means that your item as configured will be a List<Employee> instead of just an Employee. Given your configuration states it's not the real service, I'll assume that your real service should return an Employee per call and null once the results are exhausted.
To update your configuration (with your service as it is configured in your question) in your sample:
...
#StepScope
#Bean
public ItemReaderAdapter itemReader() {
ItemReaderAdapter reader = new ItemReaderAdapter();
reader.setTargetObject(service());
reader.setTargetMethod("getEmployees");
return reader;
}
#Bean
public Job methodInvokingJob() {
return this.jobBuilderFactory.get("methodInvokingJob")
.start(methodInvokingStep())
.build();
}
#Bean
public Step methodInvokingStep() {
return this.stepBuilderFactory.get("methodInvokingStep")
.<List<Employee>, List<Employee>>chunk(methodInvokingTasklet())
.reader(itemReader())
// You'll need to define a writer...
.writer(itemWriter())
.build();
}
...

Spring Data Redis with JSON converters gives "Path to property must not be null or empty."

I am trying to use a CrudRepository in association with spring-data-redis and lettuce. Following all the advice I can find I have configured my spring-boot 2.1.8 application with #ReadingConverters and #WritingConverters but when I try to use the repository I am getting "Path to property must not be null or empty."
Doing some debugging, this seems to be caused by org.springframework.data.redis.core.convert.MappingRedisConverter:393
writeInternal(entity.getKeySpace(), "", source, entity.getTypeInformation(), sink);
The second parameter being the path. This ends up at line 747 of MappingRedisConverter running this code:
} else if (targetType.filter(it -> ClassUtils.isAssignable(byte[].class, it)).isPresent()) {
sink.getBucket().put(path, toBytes(value));
}
Ultimately, the put with an empty path ends up in org.springframework.data.redis.core.convert.Bucket:77 and fails the Assert.hasText(path, "Path to property must not be null or empty."); even though the data has been serialized.
Is this a bug with spring-data-redis or have I got to configure something else?
RedicsConfig.java
#Configuration
#EnableConfigurationProperties({RedisProperties.class})
#RequiredArgsConstructor
#EnableRedisRepositories
public class RedisConfiguration {
private final RedisConnectionFactory redisConnectionFactory;
#Bean
public RedisTemplate<?, ?> redisTemplate() {
RedisTemplate<byte[], byte[]> template = new RedisTemplate<byte[], byte[]>();
template.setConnectionFactory(redisConnectionFactory);
template.afterPropertiesSet();
return template;
}
#Bean
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.findAndRegisterModules();
return objectMapper;
}
#Bean
public RedisCustomConversions redisCustomConversions(List<Converter<?,?>> converters) {
return new RedisCustomConversions(converters);
}
}
I've just included one writing converter here but have several reading and writing ones...
#Component
#WritingConverter
#RequiredArgsConstructor
#Slf4j
public class CategoryWritingConverter implements Converter<Category, byte[]> {
private final ObjectMapper objectMapper;
#Setter
private Jackson2JsonRedisSerializer<Category> serializer;
#Override
public byte[] convert(Category category) {
return getSerializer().serialize(category);
}
private Jackson2JsonRedisSerializer<Category> getSerializer() {
if (serializer == null) {
serializer = new Jackson2JsonRedisSerializer<>(Category.class);
serializer.setObjectMapper(objectMapper);
}
return serializer;
}
}
The object to write:
#Data
#JsonInclude(JsonInclude.Include.NON_NULL)
#EqualsAndHashCode(onlyExplicitlyIncluded = true)
#AllArgsConstructor
#NoArgsConstructor
#RedisHash("category")
#TypeAlias("category")
public class Category {
#Id
#EqualsAndHashCode.Include
private String categoryCode;
private String categoryText;
}
And the repo:
public interface CategoryRepository extends CrudRepository<Category, String> {
Page<Category> findAll(Pageable pageable);
}
Can anybody advise what I have missed or if this is a bug I should raise on spring-data-redis?

axon org.axonframework.commandhandling.NoHandlerForCommandException: No node known to accept

When trying to implement a DistributedCommandBus using Spring Cloud, I am getting the following error intermittently. I have reason to believe that there is some sort of race condition happening with the auto-configuration of my aggregate root class, its command handlers, and my configuration bean class.
org.axonframework.commandhandling.NoHandlerForCommandException: No
node known to accept.
I am using Axon Version 3.3.5.
Here is my configurations class:
#Configuration
#AutoConfigureBefore(CustomerAggregate.class)
public class AxonConfig {
#Value("${mongo.servers}")
private String mongoUrl;
#Value("${mongo.db}")
private String mongoDbName;
#Value("${axon.events.collection.name}")
private String eventsCollectionName;
#Value("${axon.snapshot.collection.name}")
private String snapshotCollectionName;
#Value("${axon.saga.collection.name}")
private String sagaCollectionName;
#Bean
#Primary
public CommandGateway commandGateway(#Qualifier("distributedBus") DistributedCommandBus commandBus) throws Exception {
return new DefaultCommandGateway(commandBus, new IntervalRetryScheduler(Executors.newSingleThreadScheduledExecutor(), 1000, 10));
}
#Bean
#Primary
#Qualifier("springCloudRouter")
public CommandRouter springCloudCommandRouter(DiscoveryClient client, Registration localServiceInstance) {
return new SpringCloudCommandRouter(client, localServiceInstance, new AnnotationRoutingStrategy());
}
#Bean
#Primary
#Qualifier("springCloudConnector")
public SpringHttpCommandBusConnector connector() {
return new SpringHttpCommandBusConnector(new SimpleCommandBus(), new RestTemplate(), new JacksonSerializer());
}
#Bean
#Primary
#Qualifier("distributedBus")
public DistributedCommandBus springCloudDistributedCommandBus(#Qualifier("springCloudRouter") CommandRouter router) {
return new DistributedCommandBus(router, connector());
}
#Bean
#Primary
public AggregateFactory<CustomerAggregate> aggregateFactory(){
return new GenericAggregateFactory<CustomerAggregate>(CustomerAggregate.class);
}
#Bean
#Primary
public EventCountSnapshotTriggerDefinition countSnapshotTriggerDefinition(){
return new EventCountSnapshotTriggerDefinition(snapShotter(), 3);
}
#Bean
#Primary
public Snapshotter snapShotter(){
return new AggregateSnapshotter(eventStore(), aggregateFactory());
}
#Bean
#Primary
public EventSourcingRepository<CustomerAggregate> customerAggregateRepository(){
return new EventSourcingRepository<>(aggregateFactory(), eventStore(), countSnapshotTriggerDefinition());
}
#Bean(name = "axonMongoTemplate")
public MongoTemplate axonMongoTemplate() {
return new DefaultMongoTemplate(mongoClient(), mongoDbName)
.withDomainEventsCollection(eventsCollectionName)
.withSnapshotCollection(snapshotCollectionName)
.withSagasCollection(sagaCollectionName);
}
#Bean
public MongoClient mongoClient() {
MongoFactory mongoFactory = new MongoFactory();
mongoFactory.setMongoAddresses(Arrays.asList(new ServerAddress(mongoUrl)));
return mongoFactory.createMongo();
}
#Bean
#Primary
public MongoEventStorageEngine engine() {
return new MongoEventStorageEngine(new JacksonSerializer(), null, axonMongoTemplate(), new DocumentPerEventStorageStrategy());
}
#Bean
#Primary
public EventStore eventStore() {
return new EmbeddedEventStore(engine());
}
}
And here is my aggregate class with command handlers:
#Aggregate(repository = "customerAggregateRepository")
public class CustomerAggregate {
Logger logger = LoggerFactory.getLogger(this.getClass());
#AggregateIdentifier
private String id;
private String firstName;
private String lastName;
private String email;
private CustomerAggregate() {}
public String getId() {
return id;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public String getEmail() {
return email;
}
#CommandHandler
public CustomerAggregate(CreateCustomer cmd) {
logger.debug("Received creation command: " + cmd.toString());
apply(new CustomerCreated(cmd.getId(),cmd.getFirstName(),cmd.getLastName(), cmd.getEmail()));
}
#CommandHandler
public void on(UpdateCustomer cmd) {
logger.debug("Received update command: " + cmd.toString());
apply(new CustomerUpdated(this.id,cmd.getFirstName(),cmd.getLastName(), cmd.getEmail()));
}
#CommandHandler
public void on(UpdateCustomerEmail cmd) {
logger.debug("Received update command for existing customer: " + cmd.toString());
apply(new CustomerUpdated(cmd.getId(), this.firstName, this.lastName, cmd.getEmail()));
}
// Various event handlers...
}
Any help is much appreciated.

Resources