IntelliJ cannot autowire the parameter in #ServiceActivator method if I use #EnableAutoConfiguration - spring-boot

With auto configuration enabled, my Spring Integration service activator gives me an error in IntelliJ: "Could not autowire. No beans of 'String' type found."
If I disable auto configuration, the error goes away.
Can I exclude a class from auto configuration to "fix" this? How do I know which?
Here's the #ServiceActivator:
#Slf4j
#MessageEndpoint
public class StringProcessor {
#ServiceActivator(inputChannel = "channel1")
public void processString(String s) {
log.info(s);
}
}
IntelliJ error message
The error can be toggled by the #EnableAutoConfiguration (#SpringBootApplication) annotation:
//#SpringBootApplication
#ComponentScan
#Configuration
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
How do I figure out if this is an IntelliJ false alarm, a Spring Integration issue, or am I holding it wrong? ;o)

That's IntelliJ IDEA false alarm and wrong assumption at the same time.
The signature and structure of that #ServiceActivator was never designed for injections.
Such a method is called at runtime when a message is appeared in that channel1. So, an endpoint activate that service method and passes a payload of message into an s argument of the method. With respective converting if necessary. The atuwiring assumption over there is a bug in the IDE.
See more about service activator in the docs: https://docs.spring.io/spring-integration/reference/html/messaging-endpoints.html#service-activator

It is a false alarm, and somebody has raised this as an issue with JetBrains
https://youtrack.jetbrains.com/issue/IDEA-264916
Would you mind clicking the thumbs up next to the title so Jetbrains knows that other people would like this issue fixed.
In the meantime you can disable the introspection at the method level with the following
#Slf4j
#MessageEndpoint
public class StringProcessor {
#SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
#ServiceActivator(inputChannel = "channel1")
public void processString(String s) {
log.info(s);
}
}
This type of warning is always a 'best guess' from IDEA, and as configs get more complicated, particular if you are refering to beans created in external jars it will happen more often.
They do not stop compilation or initial execution, but Spring itself will terminate execution if the warning is actually correct.

Related

unclear circular dependency with FeignClient and Spring boot

My springboot app was working fine untill I added the following class:
#Service
#RequiredArgsConstructor
public class AutoopsClientPostBootListener implements ApplicationListener<ContextRefreshedEvent>
{
private final IAutoOpsGnsFlowInitiator gnsFlowInitator;
#Override
public void onApplicationEvent(ContextRefreshedEvent event)
{
gnsFlowInitator.startClient(event);
}
}
For some odd reason after that, I get a circular dependency error stemming from
feign client dependent on AutoopsClientPostBootListener from above.
It happens becasue IAutoOpsGnsFlowInitiator is dependent on the feign client which depend on AutoopsClientPostBootListener. But FeignClient doesn't even have any members.. (feign auto generates it) so how can it be dependent on the Listener?!!
whats the problem??
Thanks for the help
So the problem was with ApplicationListener(no idea why).
Using #EventListener solved the problem.
#EventListener
public void onApplicationEvent(ContextRefreshedEvent event)
{
gnsFlowInitator.startClient(event);
}
The issue depends on the phase of your context, once your context is initialized or changes there is a call on refresh, so you event will be fired, if you need to execute your startClient once your context is fully initialized then you #EventListener will be trigger with ContextStartedEvent which is only called once your application context was fully initialized so feign is already loaded.
Hopefully this can be helpful.

Spring cloud streams could not autowire Source.class

I am learning Spring Cloud Streams from scratch.
I tried to create a Source application like this:
import org.springframework.cloud.stream.messaging.Source; //etc
#RestController
#SpringBootApplication
#CrossOrigin
#EnableBinding(Source.class)
public class StreamsProducerApplication {
#Autowired
Source source;
#GetMapping(value="/send/{message}")
public void sendMessage(#PathVariable String message){
if(message != null){
source.output().send(MessageBuilder.withPayload(message).build());}
}
public static void main(String[] args) {
SpringApplication.run(StreamsProducerApplication.class, args);
}
}
However, I get error hint from Intellij IDEA at "Source source;" saying "Could not autowire. No beans of 'Source' type found.
I can understand that Source is a interface from where I import, but the spring official website says "Spring Cloud Stream creates an implementation of the interface for you. You can use this in the application by autowiring it" https://docs.spring.io/spring-cloud-stream/docs/current/reference/htmlsingle/
So how did I do this wrong? Thank you.
It is just the Intellij IDEA doesn't know that #EnableBinding(Source.class) is going to be a bean at runtime. There is just on such a bean definition, so tooling fails to determine what to inject in that #Autowired.
Otherwise your code is fully good and you just need to run it and play with whatever you expect from that code.
This is just an IDE false alert.
You can suppress this error in IDE by adding
#SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")

Sending a message to a specific client with Spring Websockets

So I've got a Runnable class that should invoke the method notifyUser(String username, String content) once a certain criteria is met. I've been trying to get this to work but it always fails with NullPointerExceptions. This has most likely to do with an Autowiring failure (since the Runnable class is not managed by Spring). Autowiring SimpMessagingTemplate in a Spring-managed context works just fine and the methods do what they're supposed to.
What I want to do is to invoke the method (or a similar method) convertAndSendToUser of the SimpMessagingTemplate, but I cannot autowire it in this context. Everything I've tried failed so far, which is why I assume I got some of the basic concepts wrong.
My Configuration looks like this:
#Configuration
#EnableScheduling
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/test");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/test").withSockJS();
}
}
Update: I've managed to get rid of the NullPointerException by using the following code .. but messages (convertAndSendToUser() as well as convertAndSend()) don't get picked up by the client. The developer console doesn't show any incoming messages.
AbstractApplicationContext ctx = new AnnotationConfigApplicationContext(Application.class);
ctx.getAutowireCapableBeanFactory().autowireBean(myService);
That's true because you do this:
new AnnotationConfigApplicationContext(Application.class);
in that your class, meaning starting a new full appicationContext. But your user is registered in the another context.
It isn't clear why you can't make your component managed by Spring, but there is no other way to use SimpMessagingTemplate, if you can't reach applicationContext.
It would be better to share that your code to investigate from our side and decide how can we help there.
Maybe you can use there WebApplicationContextUtils...

Sonar complains about Spring Boot configuration

I have this class to start up the spring-cloud config server. It is a spring-boot application.
#SpringBootApplication
#EnableConfigServer
#EnableDiscoveryClient
public class ConfigServerApplication {
public static void main( String[] args ) {
SpringApplication.run( ConfigServerApplication.class, args );
}
}
The application runs fine and all my unit tests are fine. However, in our bamboo pipeline, it will initial a sonar process to analyze the code. We keep getting these minor warnings indicating the following:
Utility classes should not have a public constructor
I know that this is a minor issue, but I have been tasked with removing these from our code.
Ideally, you would mark the class final and provide a private constructor, or so all searches provide as a solution. However, a Spring Configuration class cannot be made final and cannot have a private constructor.
Any ideas how to resolve this?
I'm afraid this isn't a problem spring-boot or spring-cloud can solve. You need to add exceptions to your sonar configuration.
Adjusting your sonar settings would be a nicer approach of course, but if you want to please the machine spirits, you can simply add a non-static dummy function to your class, making it "non-utility" in the eyes of the Sonar checker.
It's easy to test:
#RunWith(SpringRunner.class)
#SpringBootTest
public class YourApplicationTest {
#Test
public void shouldLoadApplicationContext() {
}
#Test
public void applicationTest() {
YourApplication.main(new String[] {});
}
}
Now Sonar is saying, this is tested!
(Kudos goes out to: Robert # https://stackoverflow.com/a/41775613/863403)

Spring cloud aws (messaging) - not getting message

I am attempting to get spring cloud to work with messaging using auto configure.
My properties file contains:
cloud.aws.credentials.accessKey=xxxxxxxxxx
cloud.aws.credentials.secretKey=xxxxxxxxxx
cloud.aws.region.static=us-west-2
My Configuration class is as follows:
#ComponentScan
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
My Listener class:
#RestController
public class OrderListener {
#MessageMapping("orderQueue")
public void orderListener(Order order){
System.out.println("Order Name " + order.getName());
System.out.println("Order Url" + order.getUrl());
}
}
However, nothing seems to print out. I've verified that my queue is in the right region and there is a message on the queue thats ready to be received.
Can someone please provide some guidance?
I see three possible reasons why it is not working
The OrderListener class is not scanned by the component scanner. In order to be scanned this class must be in the same package as your Application class or in a sub-package.
The spring-cloud-aws-autoconfigure artifact is missing on you classpath and therefore the AmazonSQS client is not automatically configured and the queues are not registered.
The message you have in your queue is missing a message header contentType with value application/json (for more information about this see question Spring Cloud - SQS).

Resources