How do I set custom tracer in ModelCamelContext? - java

I am implementing simple camel application using camel 3.14.0.
I start using modelcamelcontext.
But there is below exception during setting custom tracer.
2022-04-29 17:04:18.474 INFO 10264 --- [ main] target.atom.engine.EngineApplication : Started EngineApplication in 14.158 seconds (JVM running for 16.177)
2022-04-29 17:04:18.540 ERROR 10264 --- [ main] o.s.boot.SpringApplication : Application run failed
java.lang.IllegalStateException: Cannot set tracer on a started CamelContext
at org.apache.camel.impl.engine.AbstractCamelContext.setTracer(AbstractCamelContext.java:4601) ~[camel-base-engine-3.14.0.jar:3.14.0]
at target.atom.common.config.TargetAtomConfig.reloadRoutes(TargetAtomConfig.java:54) ~[classes/:na]
at target.atom.common.config.TargetAtomConfig$$FastClassBySpringCGLIB$$7b88810d.invoke(<generated>) ~[classes/:na]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.1.jar:5.3.1]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771) ~[spring-aop-5.3.1.jar:5.3.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.1.jar:5.3.1]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) ~[spring-aop-5.3.1.jar:5.3.1]
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89) ~[spring-aop-5.3.1.jar:5.3.1]
How do I set tracer in modelCamelContext?
source code
ModelCamelContext modelCamelContext = camelContext.adapt(ModelCamelContext.class);
TraceFormatter formatter = new TraceFormatter();
modelCamelContext.setTracer(formatter.getTracer(modelCamelContext));
modelCamelContext.setTracing(true);
…

Assuming that you are using Camel Spring Boot, the CamelContext can be customized thanks to a bean of type CamelContextConfiguration that is meant to be used to add custom logic before and after Spring Boot and the CamelContext have been fully started.
In your case, the idea is to add custom logic before the start up, so your code should look like this:
#Bean
CamelContextConfiguration contextConfiguration() {
return new CamelContextConfiguration() {
#Override
public void beforeApplicationStart(CamelContext context) {
// Configure the tracer before starting up the camel context
TraceFormatter formatter = new TraceFormatter();
context.setTracer(formatter.getTracer(modelCamelContext));
context.setTracing(true);
}
#Override
public void afterApplicationStart(CamelContext camelContext) {
// Nothing to do
}
};
}

Related

Springfox 3.0.0 is not working with Spring Boot 2.6.0 [duplicate]

This question already has answers here:
Spring Boot 2.6.0 / Spring fox 3 - Failed to start bean 'documentationPluginsBootstrapper'
(14 answers)
Closed 12 months ago.
Springfox 3.0.0 is not working with Spring Boot 2.6.0, after upgrading I am getting the following error
org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException: Cannot invoke "org.springframework.web.servlet.mvc.condition.PatternsRequestCondition.getPatterns()" because "this.condition" is null
at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:181)
at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:54)
at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:356)
at java.base/java.lang.Iterable.forEach(Iterable.java:75)
at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:155)
at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:123)
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:935)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:586)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:412)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:302)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1290)
at com.enkindle.AntivirusApplication.main(AntivirusApplication.java:16)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: java.lang.NullPointerException: Cannot invoke "org.springframework.web.servlet.mvc.condition.PatternsRequestCondition.getPatterns()" because "this.condition" is null
at springfox.documentation.spring.web.WebMvcPatternsRequestConditionWrapper.getPatterns(WebMvcPatternsRequestConditionWrapper.java:56)
at springfox.documentation.RequestHandler.sortedPaths(RequestHandler.java:113)
at springfox.documentation.spi.service.contexts.Orderings.lambda$byPatternsCondition$3(Orderings.java:89)
at java.base/java.util.Comparator.lambda$comparing$77a9974f$1(Comparator.java:473)
at java.base/java.util.TimSort.countRunAndMakeAscending(TimSort.java:355)
at java.base/java.util.TimSort.sort(TimSort.java:234)
at java.base/java.util.Arrays.sort(Arrays.java:1307)
at java.base/java.util.ArrayList.sort(ArrayList.java:1721)
at java.base/java.util.stream.SortedOps$RefSortingSink.end(SortedOps.java:392)
at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258)
at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258)
at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258)
at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:510)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
at springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider.requestHandlers(WebMvcRequestHandlerProvider.java:81)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.withDefaults(AbstractDocumentationPluginsBootstrapper.java:107)
at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.buildContext(AbstractDocumentationPluginsBootstrapper.java:91)
at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.bootstrapDocumentationPlugins(AbstractDocumentationPluginsBootstrapper.java:82)
at springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper.start(DocumentationPluginsBootstrapper.java:100)
at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:178)
... 19 common frames omitted
Only adding #EnableWebMvc in main class resolved the problem:
#EnableWebMvc
#SpringBootApplication
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class);
}
}
I know this does not solve your problem directly, but consider moving to springdoc which most recent release supports Spring Boot 2.6.0. Springfox is so buggy at this point that is a pain to use. I've moved to springdoc 2 years ago because of its Spring WebFlux support and I am very happy about it. Additionally, it also supports Kotlin Coroutines, which I am not sure Springfox does.
If you decide to migrate, springdoc even has a migration guide.
Up to now, Springfox 3.0.0 only works with Spring 2.6.0-M2 but not with versions above. See the open Springfox issue https://github.com/springfox/springfox/issues/3462. There you will also find some workarounds you may use until the issue is fixed.
E.g. add this Bean to your Swagger configuration:
#Bean
public static BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
return new BeanPostProcessor() {
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) {
customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
}
return bean;
}
private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) {
List<T> copy = mappings.stream()
.filter(mapping -> mapping.getPatternParser() == null)
.collect(Collectors.toList());
mappings.clear();
mappings.addAll(copy);
}
#SuppressWarnings("unchecked")
private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {
try {
Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
field.setAccessible(true);
return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
};
}
EDIT: The server starts, but no API info is returned:
No operations defined in spec!
What a mess.
EDIT 2: As mentioned by #Héctor, spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER must be added to application.properties as well, and the operations are displayed again. However, I don't know, if setting this property is possible in any cases, as it may interfere with other constraints.
for springfox 3.0.0 and springboot 2.6.1 use this config and add this tag
#Configuration #EnableWebMvc
public class SpringFoxConfig {
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
.paths(PathSelectors.any())
.build().apiInfo(getApiInfo());
}
private ApiInfo getApiInfo() {
return new ApiInfo(
"Api Usuarios",
"prueba global logic",
"1",
"TERMS OF SERVICE URL",
new Contact("Gabriel Hernández","URL","gabriel.hernandez.u#gmail.com"),
"LICENSE",
"LICENSE URL",
Collections.emptyList()
);
}
#Bean
public static BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
return new BeanPostProcessor() {
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof WebMvcRequestHandlerProvider ) {
customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
}
return bean;
}
private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) {
List<T> copy = mappings.stream()
.filter(mapping -> mapping.getPatternParser() == null)
.collect(Collectors.toList());
mappings.clear();
mappings.addAll(copy);
}
#SuppressWarnings("unchecked")
private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {
try {
Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
field.setAccessible(true);
return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
};
}
}
A possible solution is to:
1- Set up spring.mvc.pathmatch.matching-strategy: ant_path_matcher in application.properties
2- Add the following bean to your SwaggerConfig class:
#Bean
public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(WebEndpointsSupplier webEndpointsSupplier, ServletEndpointsSupplier servletEndpointsSupplier, ControllerEndpointsSupplier controllerEndpointsSupplier, EndpointMediaTypes endpointMediaTypes, CorsEndpointProperties corsProperties, WebEndpointProperties webEndpointProperties, Environment environment) {
List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
allEndpoints.addAll(webEndpoints);
allEndpoints.addAll(servletEndpointsSupplier.getEndpoints());
allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());
String basePath = webEndpointProperties.getBasePath();
EndpointMapping endpointMapping = new EndpointMapping(basePath);
boolean shouldRegisterLinksMapping = this.shouldRegisterLinksMapping(webEndpointProperties, environment, basePath);
return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, endpointMediaTypes, corsProperties.toCorsConfiguration(), new EndpointLinksResolver(allEndpoints, basePath), shouldRegisterLinksMapping, null);
}
private boolean shouldRegisterLinksMapping(WebEndpointProperties webEndpointProperties, Environment environment, String basePath) {
return webEndpointProperties.getDiscovery().isEnabled() && (StringUtils.hasText(basePath) || ManagementPortType.get(environment).equals(ManagementPortType.DIFFERENT));
}
Credits to hhhhsw
I faced the same issue in the last project and it seems that Springfox dependency got issue with the spring 2.6.x.
I found out what is the issue it's about the Springfox dependency all the spring developers facing the same issue after spring 2.6.X
so all of them give the recommendation to migrate to springdoc. you can find everything here:
https://springdoc.org/#migrating-from-springfox
Migration Steps:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
Maintain only above dependency.
Remove library inclusions of earlier releases. Specifically remove springfox-swagger2 and springfox-swagger-ui inclusions.
Remove the #EnableSwagger2 annotations
Add the springfox-boot-starter
Springfox 3.x removes dependencies on guava and other 3rd party libraries (not zero dep yet! depends on spring plugin and open api libraries for annotations and models) so if you used guava predicates/functions those will need to transition to java 8 function interfaces
If you are using WebMvc and it's a non-springboot project, but you don’t use the #EnableWebMvc annotation yet, add this annotation.
source: doc_link
I put the dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
And remove:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Here resolved!

Exclude config classes from spring context

I have a class that configures Cassandra database:
#Configuration
#EnableCassandraRepositories(basePackages = { BASE_PACKAGE })
public class CassandraConfig {
#Value("${spring.data.cassandra.contact-points}")
private String contactPoints;
#Value("${spring.data.cassandra.keyspace-name}")
private String keyspaceName;
#Value("${spring.data.cassandra.datacenter-name}")
private String datacenterName;
#Value("${spring.data.cassandra.port}")
private int port;
#Bean
public CqlSessionFactoryBean session() {
CqlSessionFactoryBean session = new CqlSessionFactoryBean();
session.setContactPoints(contactPoints);
session.setKeyspaceName(keyspaceName);
session.setLocalDatacenter(datacenterName);
session.setPort(port);
return session;
}
...
}
And I have an empty test that just loads spring context
#SpringBootTest
class ApplicationTest {
#Test
void contextLoads() {
}
}
When I run it, I see this exception message:
Failed to load ApplicationContext
java.lang.IllegalStateException: Failed to load ApplicationContext
...
Caused by: com.datastax.oss.driver.api.core.AllNodesFailedException: Could not reach any contact point, make sure you've provided valid addresses (showing first 1 nodes, use getAllErrors() for more): Node(endPoint=127.0.0.1/<unresolved>:9042, hostId=null, hashCode=29caef8c): [com.datastax.oss.driver.api.core.connection.ConnectionInitException: [s0|control|connecting...] Protocol initialization request, step 1 (OPTIONS): failed to send request (io.netty.channel.StacklessClosedChannelException)]
at app//com.datastax.oss.driver.api.core.AllNodesFailedException.copy(AllNodesFailedException.java:141)
at app//com.datastax.oss.driver.internal.core.util.concurrent.CompletableFutures.getUninterruptibly(CompletableFutures.java:149)
at app//com.datastax.oss.driver.api.core.session.SessionBuilder.build(SessionBuilder.java:835)
at app//org.springframework.data.cassandra.config.CqlSessionFactoryBean.buildSystemSession(CqlSessionFactoryBean.java:498)
at app//org.springframework.data.cassandra.config.CqlSessionFactoryBean.afterPropertiesSet(CqlSessionFactoryBean.java:451)
at app//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1863)
at app//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800)
... 166 more
Suppressed: com.datastax.oss.driver.api.core.connection.ConnectionInitException: [s0|control|connecting...] Protocol initialization request, step 1 (OPTIONS): failed to send request (io.netty.channel.StacklessClosedChannelException)
at app//com.datastax.oss.driver.internal.core.channel.ProtocolInitHandler$InitRequest.fail(ProtocolInitHandler.java:356)
at app//com.datastax.oss.driver.internal.core.channel.ChannelHandlerRequest.writeListener(ChannelHandlerRequest.java:87)
at app//io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:578)
at app//io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:552)
at app//io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:491)
at app//io.netty.util.concurrent.DefaultPromise.addListener(DefaultPromise.java:184)
at app//io.netty.channel.DefaultChannelPromise.addListener(DefaultChannelPromise.java:95)
at app//io.netty.channel.DefaultChannelPromise.addListener(DefaultChannelPromise.java:30)
at app//com.datastax.oss.driver.internal.core.channel.ChannelHandlerRequest.send(ChannelHandlerRequest.java:76)
at app//com.datastax.oss.driver.internal.core.channel.ProtocolInitHandler$InitRequest.send(ProtocolInitHandler.java:193)
at app//com.datastax.oss.driver.internal.core.channel.ProtocolInitHandler.onRealConnect(ProtocolInitHandler.java:124)
at app//com.datastax.oss.driver.internal.core.channel.ConnectInitHandler.lambda$connect$0(ConnectInitHandler.java:57)
at app//io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:578)
at app//io.netty.util.concurrent.DefaultPromise.notifyListeners0(DefaultPromise.java:571)
at app//io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:550)
at app//io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:491)
at app//io.netty.util.concurrent.DefaultPromise.setValue0(DefaultPromise.java:616)
at app//io.netty.util.concurrent.DefaultPromise.setFailure0(DefaultPromise.java:609)
at app//io.netty.util.concurrent.DefaultPromise.tryFailure(DefaultPromise.java:117)
at app//io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.fulfillConnectPromise(AbstractNioChannel.java:321)
at app//io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.finishConnect(AbstractNioChannel.java:337)
at app//io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:707)
at app//io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)
at app//io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)
at app//io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
at app//io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986)
at app//io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at app//io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base#17.0.1/java.lang.Thread.run(Thread.java:833)
Suppressed: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: /127.0.0.1:9042
Caused by: java.net.ConnectException: Connection refused
at java.base/sun.nio.ch.Net.pollConnect(Native Method)
at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:672)
at java.base/sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:946)
at io.netty.channel.socket.nio.NioSocketChannel.doFinishConnect(NioSocketChannel.java:330)
at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.finishConnect(AbstractNioChannel.java:334)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:707)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: io.netty.channel.StacklessClosedChannelException
at io.netty.channel.AbstractChannel$AbstractUnsafe.flush0()(Unknown Source)
As I understand, it tries to connect to the database but it cannot, thus, it fails.
I tried different ways to exclude this class from context loading like #EnableAutoConfiguration(exclude = CassandraConfig.class) but then it fails with
java.lang.IllegalStateException: The following classes could not be excluded because they are not auto-configuration classes: com.myproject.test.config.CassandraConfig
Is there some advices or best practices how to solve this problem?
The error you're getting makes sense, CassandraConfig is not an autoconfiguration but a configuration class.
To exclude it you could use a Spring profile:
#Configuration
#Profile("!test")
public class CassandraConfig {
Then in your test class:
#SpringBootTest(properties = "spring.profiles.active=test")
class ApplicationTest {

Is it possible to build a #AfterThrowing advice on any execution with a given exception type?

So I have a working example of an advice that should run after an exception is thrown with a specific annotation above it. So ExtendedErrorHandling is the annotation used above a class and/or method. When that method returns a specific error of type ExtendedHttpResponseException, the advice should run.
However, the original idea was to do this without annotations.
AS-IS:
#AfterThrowing(pointcut = "execution(* *(..)) && (extendedThrowingInMethod() || extendedThrowingInClass())", throwing = "ex")
TO-BE:
#AfterThrowing(pointcut = "execution(* *(..))", throwing = "ex")
When we try to achieve this, spring refuses to start, with a very generic error message "tomcat could not startup", but also hinting that the advice isn't ok.
The error:
Caused by: org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:142)
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.<init>(TomcatWebServer.java:104)
at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getTomcatWebServer(TomcatServletWebServerFactory.java:473)
at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getWebServer(TomcatServletWebServerFactory.java:206)
at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory$$FastClassBySpringCGLIB$$9c83fa9f.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:783)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753)
at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:64)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:698)
at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory$$EnhancerBySpringCGLIB$$78134ef1.getWebServer(<generated>)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:182)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:160)
... 78 more
Caused by: java.lang.IllegalStateException: StandardEngine[Tomcat].StandardHost[localhost].TomcatEmbeddedContext[] failed to start
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.rethrowDeferredStartupExceptions(TomcatWebServer.java:187)
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:126)
... 96 more
The aspect completely:
#Aspect
#Component
public class ExtendedHttpResponseExceptionCatcherAdvisor {
#Pointcut("#annotation(com.atlascopco.common.dto.handlers.annotations.ExtendedErrorHandling)")
public void extendedThrowingInMethod() {
}
#Pointcut("#within(com.atlascopco.common.dto.handlers.annotations.ExtendedErrorHandling)")
public void extendedThrowingInClass() {
}
#AfterThrowing(pointcut = "execution(* *(..)) && (extendedThrowingInMethod() || extendedThrowingInClass())", throwing = "ex")
public void handleThrownKnownExceptions(ExtendedHttpResponseException ex) {
ResponseContext responseContext = ResponseContextHolder.getResponseContext();
GenericHttpResponseModel responseModel = responseContext.getResponseModel();
responseModel.getErrors().add(ex);
responseContext.setResponseModel(responseModel);
}
}
So the questions here are: Why does spring crash in the TO-BE situation? And is it possible to achieve the TO-BE situation without any problems, or do we run against some limitations?
Thanks for your help in advance!
Thanks to #R.G.
The solution is to be more specific when it comes to class definition. EG:
execution(* com.your.project..*(..))

Trouble configuring SpringBootApplication to read from properties

I'm struggling to load my configuration in my simple SpringBootApplication. When I attempt to print out the variables in my configuratrion class, they are always null.
Initially I had my configurable variables in WatchApplication.java. However, all of the variables I thought would be read from configuration were still null. The configuration was at /main/resources/application.properties. I've since added a class just to hold the configuration that I plan to read in WatchApplication called WatchConfiguration.
I'm new to Spring and am feeling terminally stupid
The Structure of my classes is:
-main
|--java
| |--WatchApplication.java
| |--WatchConfiguration.java
|
|--resources
|--application.properties
Here's WatchApplication.java
#SpringBootApplication
public class WatchApplication {
private WatchConfiguration configuration;
public static void main(String[] args)
{
SpringApplication.run(WatchApplication.class, args);
}
/**
* Initialize the application
*/
#PostConstruct
public void initialize()
{
configuration = new WatchConfiguration();
System.out.println(configuration.getVideoDirectory());
}
}
Here is what my WatchConfiguration.java looks like
#Configuration
public class WatchConfiguration {
#Value("${video.output.directory}")
private String videoDirectory;
#Value("${target.sites}")
private List<String> targetSites;
public WatchConfiguration getWatchConfiguration ()
{
return new WatchConfiguration();
}
public String getVideoDirectory() {
return videoDirectory;
}
public void setVideoDirectory(String videoDirectory) {
this.videoDirectory = videoDirectory;
}
public List<String> getTargetSites() {
return targetSites;
}
public void setTargetSites(List<String> targetSites) {
this.targetSites = targetSites;
}
}
And my application.properties
video.output.directory = C:\\Users\\Alex\\Desktop\\output
# Target Sites
target.sites[0] = https://youtube.com
target.sites[1] = https://bing.com
Here is the output. Note the 'null' in the console that is supposed to be the video.output.directory property value.
[2019-09-04 20:09:00.752] - 16812 INFO [restartedMain] --- com.pirate.baywatch.BaywatchApplication: Starting BaywatchApplication on DESKTOP-ULP9VBQ with PID 16812 (C:\Users\Alex\IdeaProjects\baywatch\target\classes started by Alex in C:\Users\Alex\IdeaProjects\baywatch)
[2019-09-04 20:09:00.765] - 16812 INFO [restartedMain] --- com.pirate.baywatch.BaywatchApplication: No active profile set, falling back to default profiles: default
[2019-09-04 20:09:00.792] - 16812 INFO [restartedMain] --- org.springframework.boot.devtools.env.DevToolsPropertyDefaultsPostProcessor: Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
null
[2019-09-04 20:09:01.142] - 16812 WARNING [restartedMain] --- org.springframework.context.annotation.AnnotationConfigApplicationContext: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'baywatchConfiguration': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'target.sites' in value "${target.sites}"
[2019-09-04 20:09:01.148] - 16812 INFO [restartedMain] --- org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener:
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
[2019-09-04 20:09:01.154] - 16812 SEVERE [restartedMain] --- org.springframework.boot.SpringApplication: Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'baywatchConfiguration': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'target.sites' in value "${target.sites}"
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:380)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1411)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:592)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:845)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:743)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:390)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:312)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1214)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1203)
at com.pirate.baywatch.BaywatchApplication.main(BaywatchApplication.java:16)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'target.sites' in value "${target.sites}"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:178)
at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:124)
at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:237)
at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:211)
at org.springframework.context.support.PropertySourcesPlaceholderConfigurer.lambda$processProperties$0(PropertySourcesPlaceholderConfigurer.java:175)
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:851)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1192)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1171)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:593)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:374)
... 21 more
Solution
Solved by adding #Autowired to the member variable and removing the initialization of the configuration class from the initialize method
#SpringBootApplication
public class WatchApplication {
#Autowired
private WatchConfiguration configuration;
public static void main(String[] args)
{
SpringApplication.run(WatchApplication.class, args);
}
/**
* Initialize the application
*/
#PostConstruct
public void initialize()
{
System.out.println(configuration.getVideoDirectory());
}
}
The problem is that you are creating configuration by yourself, with new. You should #Autowired it from context in to your application class.
Remove this line configuration = new Watch Configuration and add #Autowired to definition of configuration. I would also suggest you to use configuration properties instead.

Spring integration : Not able to send the message to channel

I am using spring-framework and spring-integration latest versions and just making POC application with spring integration but can't run this.
I have spring integration confing something like this.
<bean id="initUrlQ" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="initUrl.Q" />
</bean>
<int:channel id="initChannelProducerId" />
<jms:outbound-channel-adapter id="initOutboundId" channel="initChannelProducerId" connection-factory="padtoys.jms.cachedConnectionFactory"
destination="initUrlQ" />
<int:channel id="initChannelConsumerId" />
<jms:message-driven-channel-adapter id="initQListenerId" channel="initChannelConsumerId"
connection-factory="padtoys.jms.cachedConnectionFactory" destination="initUrlQ"
acknowledge="auto" concurrent-consumers="1" max-concurrent-consumers="1" />
<int:service-activator method="testSA" ref="testBean" input-channel="initChannelConsumerId" output-channel="nullChannel"/>
And my testBean java file looks like this.
public class TestBean implements ApplicationContextAware {
private ApplicationContext applicationContext;
#PostConstruct
public void afterInit(){
System.err.println("after init..!");
DirectChannel inChannel = applicationContext.getBean("initChannelProducerId", DirectChannel.class);
System.err.println("channel::" + inChannel);
inChannel.send(createMessage("This is test url!!", 0));
}
#Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
#ServiceActivator
public String testSA(){
System.err.println("inside service activator!!!");
return "this is test";
}
private Message<String> createMessage(final String url, final int depth) {
return MessageBuilder.withPayload(StringUtils.EMPTY)
.setHeader(MESSAGE_HEADERS.URL, url)
.setHeader(MESSAGE_HEADERS.DEPTH, depth).build();
}
}
And I am starting my application something like this.
#SuppressWarnings("resource") public static void main(String[] args) {
LOG.info("Trigerring process!");
new ClassPathXmlApplicationContext("/application-context.xml");
}
Please consider that I have declared testBean and padtoys.jms.cachedConnectionFactory in spring context xml.
PROBLEM :
When I start the application, getting below error
Caused by: org.springframework.messaging.MessageDeliveryException: Dispatcher has no subscribers for channel 'org.springframework.context.support.ClassPathXmlApplicationContext#5a1198c7.initChannelProducerId'.; nested exception is org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:423)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:373)
at com.dodax.pad.ext.toys.crawler.scanner.TestBean.afterInit(TestBean.java:25)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:366)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:311)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:134)
... 30 more
Caused by: org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers
at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:138)
at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:105)
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:73)
NOTE :
I am getting right channel name at this line,
System.err.println("channel::" + inChannel);, but problem starts when I try to send the message to channel.
You must not perform messaging (send()) in a #PostConstruct method - it is too early in the application context lifecycle; the context is not yet ready to perform messaging.
See this answer for the proper place to perform messaging during startup.

Categories

Resources