No handler was subscribed to command. Axon 3.3 - spring-boot

I'm attempting to create basic Axon/Spring application by tutorial, but faced with strange error like: NoHandlerForCommandException: No handler was subscribed to command. It seems that Axon can't see #CommandHandler annotation.
Here my files:
aggregate
#Aggregate
#NoArgsConstructor
public class Account {
#AggregateIdentifier
private UUID accountId;
private Double balance;
#CommandHandler
public Account(CreateAccountCommand command) {
apply(new AccountCreatedEvent(command.getAccountId(), command.getName()));
}
#EventSourcingHandler
protected void on(AccountCreatedEvent event) {
this.accountId = event.getAccountId();
this.balance = 0.0;
}
}
event
#AllArgsConstructor
#Getter
public class AccountCreatedEvent {
private UUID accountId;
private String name;
}
command
#Getter
public class CreateAccountCommand {
#TargetAggregateIdentifier
private UUID accountId;
private String name;
public CreateAccountCommand(UUID accountId, String name) {
this.accountId = accountId;
this.name = name;
}
}
spring boot conf
#SpringBootApplication
public class App {
#Configuration
public static class TestConfiguration {
#Bean
public EventStorageEngine inMemoryEventStorageEngine() {
return new InMemoryEventStorageEngine();
}
}
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
this is how i send cmd
#Component
public class AppLoader {
#Autowired
private CommandGateway cmdGateway;
#PostConstruct
public void init() {
cmdGateway.send(new CreateAccountCommand(UUID.randomUUID(), "test"));
}
}
my build.gradle
buildscript {
ext {
springBootVersion = '2.0.5.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
group = 'io.yourpoint.nettnews'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
testCompile group: 'org.axonframework', name: 'axon-test', version: '3.3.5'
compile group: 'org.axonframework', name: 'axon-spring-boot-starter', version: '3.3.5'
compile('org.springframework.boot:spring-boot-starter-webflux')
compileOnly('org.projectlombok:lombok')
testCompile('org.springframework.boot:spring-boot-starter-test')
testCompile('io.projectreactor:reactor-test')
}

It is very likely that performing the CommandGateway#send() call in a #PostConstruct is to early for Axon..
As it currently stands, all the command, event and query handlers typically get registered after all your beans have been initialized.
Moving the CommandGateway#send() behind a REST endpoint should give you a big enough time frame to ensure all the handlers have been registered.
So in short, it's a timing issues why you get the NoHandlerForCommandException.
We (at AxonIQ) see benefit in sending some sort of application events as soon as all the handlers have been registered. That's a thing for the future though.
Hope this helps you out #Benjamin!

Related

MapStruct and Immutables

I am having trouble getting mapstruct and immutables to work.
#Value.Immutable
public abstract class FoobarValue {
public abstract Integer foo();
}
#Value.Immutable
public abstract class TargetFoo {
public abstract Integer foo();
}
#Mapper
public interface ImmutableMapper {
ImmutableMapper INSTANCE = Mappers.getMapper(ImmutableMapper.class);
public TargetFoo toTarget(FoobarValue foobarValue);
}
Main class to test
public class FoobarValueMain {
public static void main(String... args) {
FoobarValue value = ImmutableFoobarValue.builder()
.foo(2)
.build();
ImmutableMapper mapper = ImmutableMapper.INSTANCE;
System.out.println(mapper.toTarget(value).foo());
}
}
The error that I get is
Exception in thread "main" java.lang.IllegalStateException: Cannot build TargetFoo, some of required attributes are not set [foo]
at org.play.ImmutableTargetFoo$Builder.build(ImmutableTargetFoo.java:158)
at org.play.ImmutableMapperImpl.toTarget(ImmutableMapperImpl.java:21)
at org.play.FoobarValueMain.main(FoobarValueMain.java:12)
My build.gradle is as follows
ext {
mapstructVersion = "1.4.0.Beta2"
immutablesVersion = "2.8.2"
}
dependencies {
annotationProcessor "org.immutables:value:$immutablesVersion" // <--- this is important
annotationProcessor "org.mapstruct:mapstruct-processor:1.4.0.Beta2"
compileOnly "org.immutables:value:$immutablesVersion"
implementation "org.mapstruct:mapstruct:${mapstructVersion}"
testCompile group: 'junit', name: 'junit', version: '4.12'
}
As per reference this should all work out of the box. What am I missing here ?
The reason why it doesn't work is because you are not using the JavaBean convention.
You need to prefix your methods with get
e.g.
#Value.Immutable
public abstract class TargetFoo {
public abstract Integer getFoo();
}

How to Autowire LdapRepository in Spring?

I am attempting to use Spring's auto-configuration to spin up an embedded LDAP server and access it using spring-data-ldap. However, the autowired fields, repository (an instance of LdapRepository) and the ldapTemplate (an instance of the LdapTemplate) are null.
For example,
spring.ldap.model.UserTest > testSaveUser FAILED
java.lang.NullPointerException at UserTest.java:32
What am I missing?
build.gradle
plugins {
id 'org.springframework.boot' version '2.0.6.RELEASE' apply false
}
apply plugin: 'io.spring.dependency-management'
apply plugin: 'java'
repositories {
jcenter()
}
dependencyManagement {
imports {
mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES
}
}
dependencies {
compile 'org.springframework.data:spring-data-ldap'
compile 'com.unboundid:unboundid-ldapsdk'
testCompile 'org.springframework.boot:spring-boot-starter-data-ldap'
testCompile 'org.springframework.boot:spring-boot-starter-test'
}
sourceCompatibility = '1.8'
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
Under src/main/java/spring/ldap/model:
Config.java
package spring.ldap.model;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.ldap.repository.config.EnableLdapRepositories;
#Configuration
#EnableLdapRepositories
public class Config { }
User.java
package spring.ldap.model;
import javax.naming.Name;
import org.springframework.ldap.odm.annotations.Attribute;
import org.springframework.ldap.odm.annotations.DnAttribute;
import org.springframework.ldap.odm.annotations.Entry;
import org.springframework.ldap.odm.annotations.Id;
#Entry(objectClasses = { "person", "top" }, base="dc=spring,dc=ldap,dc=model" )
public class User {
#Id private Name dn;
#Attribute(name = "cn") #DnAttribute(value = "cn", index = 0) private String userName;
#Attribute(name = "sn") private String fullName;
public Name getDn() { return dn; }
public void setDn(Name dn) { this.dn = dn; }
public String getUsername() { return userName; }
public void setUsername(String userName) { this.userName = userName; }
public String getFullName() { return fullName; }
public void setFullName(String fullName) { this.fullName = fullName; }
}
UserRepository.java
package spring.ldap.model;
import org.springframework.data.ldap.repository.LdapRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface UserRepository extends LdapRepository<User> { }
Under src/test/java/spring/ldap/model:
UserTest.java
package spring.ldap.model;
import static org.junit.Assert.assertNotNull;
import javax.naming.Name;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.ldap.DataLdapTest;
import org.springframework.ldap.core.DirContextAdapter;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.support.LdapNameBuilder;
import org.springframework.test.context.ContextConfiguration;
#DataLdapTest()
#ContextConfiguration(classes = Config.class)
public class UserTest {
#Autowired UserRepository repository;
#Autowired LdapTemplate ldapTemplate;
#Before
public void SetUp() {
LdapNameBuilder builder = LdapNameBuilder.newInstance();
builder.add("dc", "model");
builder.add("dc", "ldap");
builder.add("dc", "spring");
Name dn = builder.build();
DirContextAdapter context = new DirContextAdapter(dn);
context.setAttributeValues("objectclass", new String[] { "top", "domain", "extensibleObject" });
context.setAttributeValue("dc", "spring");
ldapTemplate.bind(context);
}
#Test public void testSaveUser() {
User user = new User();
user.setUsername("ncornish");
user.setFullName("Nicholas Cornish");
repository.save(user);
assertNotNull("Id was not generated!", user.getDn());
}
}
Under src/test/resources:
application.properties
spring.ldap.embedded.base-dn=dc=spring,dc=ldap,dc=model
spring.ldap.embedded.credential.username=uid=admin
spring.ldap.embedded.credential.password=secret
Must put these annotations on test class context:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = { UserRepository.class, LdapTemplate.class })
#ContextConfiguration(classes = Config.class)
#EnableConfigurationProperties
Kind regards.
Thanks JB Nezit, your comment
Your test doesn't run into a Spring context, since it's not annotated
with #RunWith(SpringRunner.class). So nothing will ever autowire
anything inside it.
resolves the issue. ie. add the following to the test class
#RunWith(SpringRunner.class)

Springboot: Required a bean of type 'javax.persistence.EntityManagerFactory' that could not be found

I am in the process of developing a Spring Boot application and came across this error when starting the server. I am not sure if I am incorrectly defining any annotations or missing any dependencies. Any help would be appreciated.
Main class:
#SpringBootApplication
#Configuration
#ComponentScan
#EnableAutoConfiguration
public class DemoApplication {
public static void main(String[] args) {
System.out.println("Hello world");
SpringApplication.run(DemoApplication.class, args);
}
}
UserService class:
#Service
public class UserService implements IUserService {
#Autowired
private UserDAO userDAO;
#Override
public List<UserDTO> getAllUsers() {
List<User> entities = userDAO.getUsers();
List<UserDTO> users = new ArrayList<UserDTO>();//Will never use directly User Object, will be using Tranferable objects
Iterator<User> iterator = entities.iterator();
while(iterator.hasNext()) {
User user = iterator.next();
users.add(ApiDTOBuilder.userToUserDTO(user));//We are building UserDTO object.
}
return users;
}
#Override
public UserDTO getUserByUsername(String username) {
User user = userDAO.getUser(username);
return ApiDTOBuilder.userToUserDTO(user);
}
#Override
public void createUser(UserDTO user) {
userDAO.createUser(ApiDTOBuilder.userDTOToUser(user));
}
#Override
public void updateUser(UserDTO user) {
userDAO.updateUser(ApiDTOBuilder.userDTOToUser(user));
}
#Override
public void deleteUser(String username) {
userDAO.deleteUser(username);
}
}
UserDAO class:
#Repository
public class UserDAO implements IUserDAO {
#PersistenceContext
EntityManager em;//JPA EntityManager is used to access a database in a particular application. It is used to manage persistent entity instances, to find entities by their primary key identity(As here is Username), and to query over all entities.
#Override
#Transactional
public User getUser(String username) {
return em.find(User.class, username); //Here entitymanager can find the username as it has the capability to find an entity by unique identifies
}
#Override
#Transactional
public List<User> getUsers() {
List<User> resultList = em.createQuery("FROM user_tbl", User.class).getResultList();
return resultList;
}
#Override
#Transactional
public void createUser(User user) {
em.persist(user);//Make an instance managed and persistent.
}
#Override
#Transactional
public void updateUser(User user) {
em.merge(user);//Merge the state of the given entity into the current persistence context.
}
#Override
#Transactional
public void deleteUser(String username) {
User user = this.getUser(username);
em.remove(user);//Remove the entity instance.
}
}
Build.gradle:
buildscript {
ext {
springBootVersion = '2.0.0.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.springframework.boot:spring-boot-starter-web')
compile('org.springframework.boot:spring-boot-starter-security')
compile('org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Final')
compile('javax.xml.bind:jaxb-api:2.2.11')
compile('org.springframework.boot:spring-boot-starter-test:2.0.2.RELEASE')
compile('com.sun.xml.bind:jaxb-core:2.2.11')
compile('com.sun.xml.bind:jaxb-impl:2.2.11')
runtime('org.springframework.boot:spring-boot-devtools')
runtime('mysql:mysql-connector-java')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
Error message:
***************************
APPLICATION FAILED TO START
***************************
Description:
Field userDAO in com.example.demo.service.UserService required a bean of type 'javax.persistence.EntityManagerFactory' that could not be found.
Action:
Consider defining a bean of type 'javax.persistence.EntityManagerFactory' in your configuration.
I saw all the relevant answers and tried to implement those suggestions like adding dependencies, adding notations in the main class, etc. But it shows the same error. Please someone help me out. Thank you in advance.
P.S: Github link of my application: https://github.com/heliOpenxCell/demo
i got the same your problem, just add this to your maven or gradle, it work for me!
Maven:
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
<version>9.0.10</version>
</dependency>
Gradle:
compile group: 'org.apache.tomcat', name: 'tomcat-jdbc', version: '9.0.10'

Spring boot application(not web) stops after start

I have google cloud pubsub subscriber application(question is not related to pubsub, i believe there is same behaviour with jms listener). It don't require any webcontainer like tomcat or other(There is plenty questions where problem was missing container dependency, here i don`t need webcontainer). It should start and process messages. The problem: it stops after start.
Application is very simple, here is build.gradle file:
buildscript {
ext {
springBootVersion = '1.5.8.RELEASE'
}
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
compile 'org.springframework.boot:spring-boot-starter'
}
And here is application launcher:
#SpringBootApplication
public class CommunicationApplication {
public static void main(String[] args) throws IOException {
SpringApplication.run(CommunicationApplication.class, args);
//waiting data from system input to prevent stop after start
//System.in.read();
}
}
And here is pubsub manager bean(it creates pubsub listener)
#Component
public class PubsubManager {
private final Logger logger = LoggerFactory.getLogger(getClass());
#Autowired
private MessageReceiver messageReceiver;
private Subscriber subscriber;
#PostConstruct
protected void start() throws Exception {
createTopic();
createSubscriber();
}
private void createTopic() throws Exception {
TopicName topic = TopicName.of(ServiceOptions.getDefaultProjectId(), "COMMUNICATION_TOPIC_NAME");
try (TopicAdminClient topicAdminClient = TopicAdminClient.create()) {
topicAdminClient.createTopic(topic);
logger.info("Topic {}:{} created", topic.getProject(), topic.getTopic());
} catch (ApiException e) {
if (e.getStatusCode().getCode() == StatusCode.Code.ALREADY_EXISTS) {
logger.info("Topic {}:{} already exist", topic.getProject(), topic.getTopic());
} else {
logger.error("Error create topic: {}", e.getStatusCode().getCode());
}
logger.info("isRetryable: {}", e.isRetryable());
}
}
private void createSubscriber() throws Exception {
SubscriptionName subscriptionName = SubscriptionName.of(ServiceOptions.getDefaultProjectId(),
MessagingConstants.COMMUNICATION_SUBSCRIPTION_NAME);
// create a subscriber bound to the asynchronous message receiver
try (SubscriptionAdminClient subscriptionAdminClient = SubscriptionAdminClient.create()) {
TopicName topicName = TopicName.of(ServiceOptions.getDefaultProjectId(),
"COMMUNICATION_TOPIC_NAME");
Subscription subscription = subscriptionAdminClient.createSubscription(
subscriptionName, topicName, PushConfig.getDefaultInstance(), 0);
} catch (Exception e) {
logger.info("subscription already created:", e);
}
subscriber = Subscriber.newBuilder(subscriptionName, messageReceiver).build();
subscriber.startAsync().awaitRunning();
logger.info("subscriber start receiving messages");
}
#PreDestroy
protected void close() throws Exception {
logger.info("subscriber stop receiving messages");
subscriber.stopAsync();
}
}
If i uncomment System.in.read(); - it works at local environment, but at cloud it don`t work. Could you suggest proper way to fix this? Thanks.
If you want to create only the PubSub Listener, the following worked for me:
git clone https://github.com/spring-guides/gs-messaging-gcp-pubsub
cd gs-messaging-gcp-pubsub/complete
Change your build.gradle file to the build.gradle file below.
cd gs-messaging-gcp-pubsub/complete/src/main/resources Once in there you can delete the static folder.
Go to gs-messaging-gcp-pubsub/complete/src/main/java/hello ; In there you should have two files: PubSubApplication.java and WebAppController.java. Remove WebAppController.java and change the PubSubApplication.java to the file below:
build.gradle:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.9.RELEASE")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
jar {
baseName = 'gs-spring-cloud-gcp'
version = '0.1.0'
}
repositories {
mavenCentral()
maven {
url "http://repo.spring.io/snapshot"
}
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
dependencies {
compile("org.springframework.cloud:spring-cloud-gcp-starter-pubsub:1.0.0.BUILD-SNAPSHOT")
compile("org.springframework.cloud:spring-integration-gcp:1.0.0.BUILD-SNAPSHOT")
}
pubSubApplication.java
package hello;
import java.io.IOException;
import com.google.cloud.pubsub.v1.AckReplyConsumer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gcp.pubsub.core.PubSubOperations;
import org.springframework.cloud.gcp.pubsub.core.PubSubTemplate;
import org.springframework.cloud.gcp.pubsub.support.GcpHeaders;
import org.springframework.context.annotation.Bean;
import org.springframework.integration.annotation.MessagingGateway;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.gcp.pubsub.AckMode;
import org.springframework.integration.gcp.pubsub.inbound.PubSubInboundChannelAdapter;
import org.springframework.integration.gcp.pubsub.outbound.PubSubMessageHandler;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
#SpringBootApplication
public class PubSubApplication {
private static final Log LOGGER = LogFactory.getLog(PubSubApplication.class);
public static void main(String[] args) throws IOException {
SpringApplication.run(PubSubApplication.class, args);
}
#Bean
public MessageChannel pubsubInputChannel() {
return new DirectChannel();
}
#Bean
public PubSubInboundChannelAdapter messageChannelAdapter(
#Qualifier("pubsubInputChannel") MessageChannel inputChannel,
PubSubOperations pubSubTemplate) {
PubSubInboundChannelAdapter adapter =
new PubSubInboundChannelAdapter(pubSubTemplate, "testSubscription");
adapter.setOutputChannel(inputChannel);
adapter.setAckMode(AckMode.MANUAL);
return adapter;
}
#Bean
#ServiceActivator(inputChannel = "pubsubInputChannel")
public MessageHandler messageReceiver() {
return message -> {
LOGGER.info("Message arrived! Payload: " + message.getPayload());
AckReplyConsumer consumer =
(AckReplyConsumer) message.getHeaders().get(GcpHeaders.ACKNOWLEDGEMENT);
consumer.ack();
};
}
}
Change "testSubscription" to the Subscription you are using
Now in folder gs-messaging-gcp-pubsub/complete, if you run ./gradlew bootRun the app hello.PubSubApplication should get running on local. Any message you publish to the Topic where you are subscribed should appear where you are running the app.
If you have problems with credentials/authenticaion change the parameters in:
gs-messaging-gcp-pubsub/complete/src/main/resources/application.properties

AOP not working in Spring Boot

I'm working on AOP for the first time. It's not working - Maybe I'm mixing up Spring AOP and AspectJ, I'm not sure.
dependency declaration in Gradle file
dependencies {
compile fileTree(dir: 'libs', include: '*.jar')
...
compile("org.aspectj:aspectjweaver:1.8.9")
}
}
Configuration class
#Configuration
#EnableAspectJAutoProxy
public class AspectJConfiguration{
#Bean
public MailQueueServiceAspect mailQueueServiceAspect(){
return new MailQueueServiceAspect();
}
}
Aspect Class
#Aspect
public class MailQueueServiceAspect {
private final Logger log = LoggerFactory.getLogger(MailQueueServiceAspect.class);
#Pointcut("execution(* com.biscom.bsend.core.SaveMailHelper.aopTest())")
private void mailUpdatePointCut(){}
#After("mailUpdatePointCut()")
public void afterSampleCreation(JoinPoint joinPoint) {
log.info("Mail Queue updated successfully.");
}
}
Joint-Point holder class
public class SaveMailHelper extends AbstractHelper<SaveMailInput, SaveMailOutput> {
#Inject
private MailQueueService mailQueueService;
private final Logger log = LoggerFactory.getLogger(SaveMailHelper.class);
#Override
protected void executeHelper(SaveMailInput input, SaveMailOutput output) throws AbstractException {
MailQueue mailQueue = mailQueueService.get(input.getId(), new MailQueue());
BlockExecutor e = new BlockExecutor();
e.execute(input.getMailFrom().shouldSet(mailQueue.isNew(), mailQueue.getMailFrom()), () ->{
mailQueue.setMailFrom(input.getMailFrom().get());
});
output.setEntity(mailQueue);
aopTest();
}
public void aopTest(){
log.info("AOPTest method called.");
}
}
I also tried avoiding Configuration class by placing #Component annotation over Aspect class.

Resources