quarkus custom bean annotation "creating" proxies even with Singleton scope - java

I have a java library that I want to use inside a quarkus application, this library has a custom annotation that I want to use for bean loading so I wrote a quarkus extension and tried the BeanDefiningAnnotationBuildItem approach.
Extract from the extension deployment module:
static DotName OP_RULE_ANNOTATION = DotName.createSimple(OpRule.class.getName());
static DotName SINGLETON = DotName.createSimple(Singleton.class.getName());
#BuildStep
void additionalBeanAnnotations(BuildProducer<BeanDefiningAnnotationBuildItem> beanDefiningAnnotations) {
beanDefiningAnnotations.produce(new BeanDefiningAnnotationBuildItem(OP_RULE_ANNOTATION, SINGLETON, false));
}
The annotation is correctly detected and beans are loaded but when I try to inject them they are wrapped by a proxy and it looks like the Singleton scope is ignored.
Does anyone have any hint on how I can debug this?
update:
While adding tests to the extension I also added a test to ensure that those classes would have not been wrapped by a Proxy and it passed, I do not have any special config on the application (that I know of)

The issue was caused by dev-mode monitoring, disabling it with this property solves the issue:
quarkus.arc.dev-mode.monitoring-enabled
https://quarkus.io/guides/all-config#quarkus-arc_quarkus.arc.dev-mode.monitoring-enabled

Related

Build-time validation of web sockets ClientEndpoint in Quarkus

I use Java WebSocket API to declare client (Java class annotated by #ClientEndpoint):
#ClientEndpoint
public class MySock {
MySock(ExecutorService exec){}
...
}
Instance is created via constructor:
webSocket = new MySock(exec);
session = wsContainer.connectToServer(webSocket, url);
And I have error during the build via quarkus-maven-plugin:
[error]: Build step ...ArcProcessor#validate threw an exception:
javax.enterprise.inject.UnsatisfiedResolutionException:
Unsatisfied dependency for type ...ExecutorService and qualifiers [#Default]
- java member: edu.MySock#<init>()
- declared on CLASS bean [types=[edu.MySock, java.lang.Object], qualifiers=[#Default, #Any], target=edu.MySock]
Pay attention: there is no #Inject annotation
Should have it been validated, if it can be passed to #connectToServer as a class and as instance too?
So, Is it ok if validation processes a pessimistic case, where validation is useful, but it brokes an optimistic case?
Pessimistic case, where dependencies may not be declared:
session = wsContainer.connectToServer(MySock.class, url);
In the following case, validation is harmful because it brokes build phase:
session = wsContainer.connectToServer(webSocket, url);
Maybe ClientEndpoint should not be validated at all?
And before you ask me...
We are not going to inject something into WebSocket and we would not like to use programmatic EndPoints. But we want to create an instance for the annotated class. Why not? WebSocket incapsulates complex logic inside itself and this variant we used multiple times (e. g. in applications on WildFly).
The best solution for me would be to disable validation for my bean only, but I cannot find an idea of how to do it.
This article has not helped me https://quarkus.io/guides/cdi-reference. The fact that beans.xml is ignored cannot help me too.
The second-way, for the future, is to disable validation if there is no one class member with #Inject annotation. It can be not correct, but here there is some explanation:
First, the container calls the bean constructor (the default constructor or the one annotated #Inject), to obtain an instance of the bean.
So, my constructor is not "default" and I did not use #Inject annotation.
Work around is so simple: #javax.enterprise.inject.Vetoed annotation disables bean for validation.

Registering Hystrix Concurrency Strategy fails after migrating to spring-boot-2.0

Trying to register hystrix concurrency strategy fails after migrating to Spring-boot-2.0 with spring actuator enabled with java.lang.IllegalStateException stating that "Another strategy was already registered" . This is although I have not used registerConcurrencyStrategy anywhere else in my code.
I'd like to register concurrency strategy to carry-forward Log MDC context so that I'm able to log both within and outside the Hystrix wrapped method equally well, which includes thread-locals. And this used to work perfectly in spring-boot-1.5
After having migrated to spring-boot 2.0 (from 1.5), the HystrixPlugins.getInstance().registerConcurrencyStrategy(this); fails with IllegalStateException
As per https://github.com/Netflix/Hystrix/issues/1057, this issue can come if either (a) Any other code flow would have registered its own or default ConcurrencyStrategy before this is invoked (b) any call would have come via Hystrix before this is invoked
Since the above invocation is within the constructor of a class which is annotated with #Component, this should get invoked ideally before any method call happens (except initialization of other beans, including their constructors).
We even tried moving this code inside the SpringBoot Application Class's main method before invoking the SpringApplication.run(MyApplication.class, args); but that also didn't work
#Component
public class ContextCopyHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {
private static final String EVENT = "HystrixConcurrencyStrategy";
private static final String ACTION = "ContextCopy";
public ContextCopyHystrixConcurrencyStrategy(Logger logger, LoggerUtil defaultLoggerUtil) {
try {
HystrixPlugins.getInstance().registerConcurrencyStrategy(this);
} catch (IllegalStateException e) {
defaultLoggerUtil.logEvents(logger, Level.WARN, e.getMessage(), EVENT, ACTION, "", "Race condition! Could not register strategy. HystrixConcurrencyStrategy is already initialized.");
}
Expected: My registering should have happened before any other code and registering should have been successful
Actual: My registering fails with IllegalStateException
How do I make sure that my registering happens well before any other registering (which is not present in my code, but may be inside some of the libraries that I may be transitively using)
By default, Spring boot 2 accuator registers Hystrix Metric Binder beans which reset already set HystrixConcurrencyStrategy and sets HystrixConcurrencyStrategyDefault.
So, disabling that bean by
management.metrics.binders.hystrix.enabled=false
would help not resetting your custom HystrixConcurrencyStrategy
We took a close look at my maven .m2 directory classes and looked for registerConcurrencyStrategy inside all the classes in all the jars. And we found that
io.micrometer.core.instrument.binder.hystrix
was internally registering the HystrixConcurrencyStrategy with the default one.
And upon further research we found that setting the following property in application.properties:
management.metrics.binders.hystrix.enabled=false disabled the Hystrix Metrics Binder (I'm actually not sure what it does though!) and then things worked
I was using spring-boot-starter-parent v2.5.3 with Spring Cloud version 2020.0.3.
I had to manually include version for spring-cloud-starter-netflix-hystrix. I was getting "Another strategy was already registered" exception when starting my microservice. I included the
management.metrics.binders.hystrix.enabled=false
in the application.properties file and this issue got resolved.

Using EmbeddedValueResolver with #Conditional

Problem context: in our application we use custom PropertySourcesPlaceholderConfigurer to extend possibilities of EmbeddedValueResolver with custom property sources. I am very inspired of Spring Boot #ConditionalOnProperty and #ConditionalOnExpression and want to use it with custom placeholders.
What I wanted to do was to write custom #Conditional annotation that uses EmbeddedValueResolver to resolve placeholders (${...}). I noticed that ConfigurationClassPostProcessor implements ResourceLoaderAware interface, and ResourceLoaderAware classes are configured later than EmbeddedValueResolverAware ones. So when we initialize ResourceLoaderAware, our EmbeddedValueResolverAware beans are already configured. So potentially solution seems possible.
What I wanted to do next was to write custom Condition that uses EmbeddedValueResolver from ApplicationContext to resolve some property and match it to some value. But the problem is that Condition uses some another context class called ConditionContext which doesn't include EmbeddedValueResolver. Using Environment#resolvePlaceholder doesn't help - seems like Environment doesn't know anything about placeholders that are available through EmbeddedValueResolver.
So, is that possible to use EmbeddedValueResolver with Spring conditionals?

How to set up custom behavior of spring data on a CDI environment

So, I have an application running on WildFly10, which uses JSF, Spring (DI), JPA, Spring Data;
Right now we're trying to move it to CDI and remove Spring(DI). For now we'll keep Spring Data.
So, I set up CDI and made an EntityManager producer.
#Produces
#Dependent
#PersistenceContext
public EntityManager entityManager;
So, I'm able to inject repositories with CDI and all.
However on my original environment we had a custom repository factory,that was defined in my SpringConfiguration like this:
#EnableJpaRepositories(basePackages = {"com.foo.repository" }, repositoryFactoryBeanClass=CustomJpaRepositoryFactoryBean.class)
So, the question is, how can I define this repositoryFactoryBeanClass=CustomJpaRepositoryFactoryBean.class on a CDI environment?
The current implementation doesn't allow the configuration of the JpaRepositoryFactoryBean as one can see from the code where it gets instantiated.
So I guess you have the following options:
reimplement the instantiation process.
open a feature request.
do 2. and 1. in a reusable way and submit the result as a PR for the issue.
When trying to solve this problem I found that the custom impl was not being picked up. The solution suggested in this question helped me however: https://stackoverflow.com/a/38541669/188624
Basically is uses Java8 default interface method to provide the additional functionality. I had to use the "CDI.current().select" method to get hold of the entity manager though as property injection of course won't work.
I tested with Spring Data JPA 2.0.0

How to enable #Required?

How to enable the #Required annotation in Java (Spring 3.1) ? Not in a xml, but in through Java. Also under which annotation I put this enabling? Under #Feature (in #FutureConfiguration or #Bean (in #Configuration) ?
Edit:
#Feature
public MvcAnnotationDriven annotationDriven(ConversionService conversionService) {
return new MvcAnnotationDriven().conversionService(conversionService)
.argumentResolvers(new CustomArgumentResolver());
}
Does this enables all annotations?
#anubhava's answer works, but he's referenced the Spring 2.0 manual, which is 5 years old.
In XML config, Spring 3.x has a more elegant approach: <context:annotation-config/>. This also enabled a whole other bunch of features that you'll probably want, whereas RequiredAnnotationBeanPostProcessor only enables a few.
See Spring 3.x manual.
If you're using #Bean-style config, then annotations like #Required should already be enabled, since that's how #Bean works. However, it's possible that this is a bug - Spring 3.1 is still in early beta, and big chunks of it are likely to be broken.
Unless you really know what you're doing, I strongly recommend sticking to 3.0.x.
From the Spring manual:
There is one last little (small, tiny)
piece of Spring configuration that is
required to actually 'switch on' this
behavior. Simply annotating the
'setter' properties of your classes is
not enough to get this behavior. You
need to enable a component that is
aware of the #Required annotation and
that can process it appropriately.
This component is the
RequiredAnnotationBeanPostProcessor
class. This is a special
BeanPostProcessor implementation that
is #Required-aware and actually
provides the 'blow up if this required
property has not been set' logic. It
is very easy to configure; simply drop
the following bean definition into
your Spring XML configuration.
<bean class=
"org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>
Please check: http://static.springsource.org/spring/docs/2.0.x/reference/metadata.html
Use AnnotationConfigApplicationContext if you don't want to use XML:
Standalone application context,
accepting annotated classes as input -
in particular #Configuration-annotated
classes, but also plain #Components
and JSR-330 compliant classes using
javax.inject annotations. Allows for
registering classes one by one
(register(java.lang.Class...)) as well
as for classpath scanning
(scan(java.lang.String...)).
In case of multiple Configuration
classes, Bean methods defined in later
classes will override those defined in
earlier classes. This can be leveraged
to deliberately override certain bean
definitions via an extra Configuration
class.
Sample Code:
ConfigurableApplicationContext applicationContext =
new AnnotationConfigApplicationContext(
"com.mycompany.package1",
"com.mycompany.package2",
"com.mycompany.package3"
// etc.
);
applicationContext.refresh();

Categories

Resources