Non-JSR299 bean cannot be proxied for producer method - java

I understood that classes that were not JSP-299 compliant could be made available for injection if instantiated via a producer method.
This I have interpreted as meaning that if I want to make injectable a bean with a constructor that takes a parameter I can do so by the use of a producer method.
However when I do this I get the following exception on deployment:
2015-11-11T21:35:12.099+0000|Grave: Exception during lifecycle processing
org.glassfish.deployment.common.DeploymentException: CDI deployment failure:Exception List with 2 exceptions:
Exception 0 :
org.jboss.weld.exceptions.DeploymentException: WELD-001435 Normal scoped bean class org.....MongoConfiguration is not proxyable because it has no no-args constructor - Producer Method [MongoConfiguration] with qualifiers [#Any #Default] declared as [[BackedAnnotatedMethod] #Produces #ApplicationScoped public org.....PropertiesProducer.produceMongoConfiguration()].
Here is the producer:
public class PropertiesProducer {
private static final String PROPERTIES_FILE = "mongo.properties";
private Properties properties = new Properties();
public static final String DATABASE_NAME = "database.name";
public static final String PORT = "database.port";
public static final String HOST = "database.host";
public static final String USERNAME = "database.username";
public static final String PASSWORD = "database.password";
#Produces
#ApplicationScoped
public MongoConfiguration produceMongoConfiguration(){
final InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(PROPERTIES_FILE);
if (in == null) {
return new MongoConfiguration(properties);
}
try {
properties.load(in);
} catch (IOException e) {
throw new RuntimeException("Failed to load properties", e);
}
finally {
try {
if (in != null) {
in.close();
}
} catch (IOException e) {
// don't care
}
}
return new MongoConfiguration(properties);
}
}
Here is the usage:
public class MongoDatastore {
#Inject
MongoConfiguration mongoConfiguration;
#Inject
MongoClient mongoClient;
Datastore datastore;
#PostConstruct
private void setupDatastore() {
Morphia morphia = new Morphia();
datastore = morphia.createDatastore(mongoClient, mongoConfiguration.getDatabaseName());
}
}
Have I missed something really obvious?

The simplest solution is to change the scope from the #ApplicationScoped to #Singleton:
import javax.inject.Singleton;
#Produces
#Singleton
public MongoConfiguration produceMongoConfiguration(){
// ...
return new MongoConfiguration(properties);
}
For clarification you can see this SO answer.
BTW: normal scope #ApplicationScoped is usually preferred over the #Singleton pseudo-scope. Why? E.g. because a serialization + deserialization of such bean will work flawlessly. But in a daily work, sometimes we encounter a 3rd part class that is unproxyable, and we cannot change it. So possible solutions we have:
Use #Singleton pseudo-scope.
Create an interface and use that instead of the concrete bean (inside producer method return type and normal code).

Related

Cannot have inject dynamic instance in quarkus when using #Dependent

I am using a library that is not thread safe and I want a fresh instance of that library object whenever I use it. I made a test repo here : https://github.com/lud/test-quarkus-arc
The library comes with two classes, SomeLibraryClass, which I need to use, and SomeLibraryClassDependency which is required by the former, and which is the thread-unsafe one.
I was trying to get all that working by using this factory-ish class:
#ApplicationScoped
public class MyAppFactory {
#Dependent
#Produces
SomeLibraryClassDependency getDep() {
return new SomeLibraryClassDependency();
}
#Dependent
#Produces
SomeLibraryClass getUsable(SomeLibraryClassDependency dep) {
return new SomeLibraryClass(dep);
}
#Inject
Instance<MyAppClass> myClass;
public MyAppClass getNewMyClass() {
return myClass.get(); // <-- this fails
}
}
This is some test code I would like to compile. I am calling the factory getter twice, and I verify that my class uses a different instance of the SomeLibraryClassDependency class.
#Test
public void testHelloEndpoint() {
var a = factory.getNewMyClass();
var b = factory.getNewMyClass();
assertNotEquals(a.getUsabeId(), b.getUsabeId());
}
Here is the class that should be instantiated by calling Instance<MyAppClass>#get:
#Dependent
public class MyAppClass {
#Inject
SomeLibraryClass usable;
public MyAppClass() {
}
public Integer getUsabeId() {
return usable.getId();
}
}
Finally here is the code for the library mocks:
public class SomeLibraryClass {
private SomeLibraryClassDependency dep;
public SomeLibraryClass(SomeLibraryClassDependency dep) {
this.dep = dep;
}
public Integer getId() {
return dep.getId();
}
}
public class SomeLibraryClassDependency {
private static Integer n = 0;
private Integer id;
public SomeLibraryClassDependency() {
n += 1;
this.id = n;
}
public Integer getId() {
return id;
}
}
When trying to compile that, I have the following error, and I do not understand why
[error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type io.quarkus.arc.runtime.BeanContainer$Instance<org.acme.getting.started.MyAppClass> and qualifiers [#Default]
java member: org.acme.getting.started.MyAppFactory#myClass
declared on CLASS bean [types=[org.acme.getting.started.MyAppFactory, java.lang.Object], qualifiers=[#Default, #Any], target=org.acme.getting.started.MyAppFactory]
I was thinking that since MyAppClass has the #Dependent annotation, it should be resolved.
Edit: I know I can also define a producer for my class, but my end goal is to be able to #Inject other things in that class (like a logger) and let the container do its job.
The error message says Unsatisfied dependency for type io.quarkus.arc.runtime.BeanContainer$Instance<org.acme.getting.started.MyAppClass>, which suggests that you have a wrong import for the Instance class. The correct one is javax.enterprise.inject.Instance.

Context Oriented Runtime CDI Qualifiers (HK2, Guice)

I'm interested in using HK2 or Guice for a dependency injection framework.
I know of #Named, #Qualifier, and custom annotations etc. But these are all compile-time.
I am looking for a facility to dynamically determine the desired concrete type based on runtime context and inject the correct implementation.
Is there something like that in HK2 or Guice or a recommended way of achieving this?
For example:
// I would want to turn this...
public final class Handler
{
private final Session session;
#Inject
public Handler(#Named("Database") final Session session)
{
this.session = session;
}
...
}
// into something like this...
public final class Handler
{
private final Session session;
#Inject
public Handler(final Session session)
{
this.session = session;
}
}
// where "session" is injected based on some previous context value ("Database")
// or something to that effect.
I ended up using a feature in HK2 called Operations (link to docs). It allows a user of HK2 to define custom scopes and manage them as "operations". You can find a more detailed example of how to use the feature on HK2's github project: operations example.
This is a simplified example of how I ended up using this feature to inject things based on context or in this case "scope".
Here is some almost-working pseudo-code to demonstrate my usage:
// Create the custom scope annotation.
#Scope
#Proxiable(proxyForSameScope = false)
#Documented
#Target({ ElementType.TYPE, ElementType.METHOD })
#Retention(RetentionPolicy.RUNTIME)
public #interface BatchScope
{
public static final BatchScope INSTANCE = new BatchScopeEnvoy();
}
final class BatchScopeEnvoy extends AnnotationLiteral<BatchScope> implements BatchScope
{
private static final long serialVersionUID = 938233179310254573L;
}
// Create a context used by the HK2 operation feature.
#Singleton
public final class BatchScopeContext extends OperationContext<BatchScope>
{
#Override
public Class<? extends Annotation> getScope()
{
return BatchScope.class;
}
}
// Create a class that holds your custom scope data/context.
public final class BatchScopeRuntime
{
// ... Arbitrary runtime data here ...
public SomeData getData()
{
return this.data;
}
}
// Create a factory that serves up something you want to inject from a custom scope.
#Singleton
public final class DataFactory implements Factory<SomeData>
{
private final OperationManager operations;
#Inject
public BatchInfoFactory(final OperationManager operations)
{
Sentinel.assertIsNotNull(operations);
this.operations = operations;
}
// The #BatchScope on the provide() method indicates that objects returned
// from this factory are in the "BatchScope".
#Override
#BatchScope
public IBatchInfo provide()
{
final OperationHandle handle = this.operations.getCurrentOperation(BatchScope.INSTANCE);
final BatchScopeRuntime runtime = (BatchScopeRuntime)handle.getOperationData();
return runtime.getData();
}
#Override
public void dispose(final IBatchInfo instance)
{
// Do nothing.
}
}
// Setup the injector.
public static ServiceLocator createInjector(final String name)
{
final ServiceLocator injector = ServiceLocatorFactory.getInstance().create(name);
ServiceLocatorUtilities.bind(
injector,
new AbstractBinder()
{
#Override
protected void configure()
{
// This creates a "Singleton" factory that provides
// "SomeData" instances at "BatchScope".
bindFactory(DataFactory.class, Singleton.class)
.to(SomeData.class)
.in(BatchScope.class);
}
}
return injector;
}
// Create a class that needs something in the custom scope.
public final class Foo
{
#Inject
public Foo(final SomeData data)
{
System.out.printf("I got: %s%n", data);
}
}
// Usage: how to manage the scopes using the operations feature.
final SomeData data = ... // get some data
final BatchScopeRuntime runtime = new BatchScopeRuntime(data); // Setup the runtime information.
// Create an operation handle for the custom scope and associate the custom data with it.
final ServiceLocator injector = createInjector("test");
ServiceLocatorUtilities.addClasses(injector, BatchScopeContext.class, Foo.class);
final OperationManager operations = injector.getService(OperationManager.class);
final OperationHandle<BatchScope> batchScope = operations.createAndStartOperation(BatchScope.INSTANCE);
// Operation/scope is now associated with the current thread.
batchScope.setOperationData(runtime);
// Foo will now be injected with: "data" from above.
final Foo foo = injector.getService(Foo.class);
// Do some work...
// Close the operation (make it go out of scope) on the current thread.
batchScope.closeOperation();

#Autowired create null object inspite #configuration

I have the following configuration class
#org.springframework.context.annotation.Configuration
public class TemplateConfiguration {
#Bean
public Configuration configuration() {
Configuration configuration = new Configuration(new Version(2, 3, 23));
configuration.setClassForTemplateLoading(TemplateConfiguration.class, "/templates/");
configuration.setDefaultEncoding("UTF-8");
configuration.setLocale(Locale.US);
configuration.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
return configuration;
}
}
and I use it at the following #service
#Service
public class FreeMarkerService {
#Autowired
private Configuration configuration;
private static final Logger logger = LoggerFactory.getLogger(FreeMarkerService.class);
public String process() {
try {
Template template = configuration.getTemplate("someName");
....
} catch (IOException | TemplateException e) {
logger.error("Error while processing FreeMarker template: " + e);
throw new RuntimeException(e);
}
}
}
but when I try to call process() like
FreeMarkerService f = new FreeMarkerService()
f.process()
I get a null exception cause the configuration Object is null
I want to create an instance using #Autowired and #Configuration annotations
what am I doing wrong?
You should use the Spring instantiated FreeMarkerService object avoiding use of new keyword for objects like Controllers or Services as possible.
For example,
#Service
public class SampleService {
#Autowired
private FreeMarkerService freeMarkerService;
public String callProcess() {
return freeMarkerService.process();
}
}
More details you can find in many posts like this.
This is a member injection:
#Autowired
private static Configuration configuration;
Which spring does after instantiating the bean from its constructor. So at the time you are making that static method call spring has not injected the value.
This is because you are trying to autowire a static field. This is not possible in Spring. Remove static from your Configuration property and it should work.
#Autowired
private Configuration configuration;
#Autowired
private static Configuration configuration;
Why autowired a static field? this is the reason. static member load as class definition load so it is not getting injected value and getting default value which is null.

Injecting dependency to a Spring bean

I would like to inject a singleton object dependency to a Spring bean. The catch is that I can't access and modify the class whose object I want to be injected. Let me describe on the example.
So I have my interface, and the implementation of this interface, like the following.
public interface MyServiceProxy {
String BEAN_NAME = "MyServiceProxy";
Data getData(String dataId);
}
public class MyServiceProxyImpl implements MyServiceProxy {
private final MyServiceClient client;
public MyServiceProxyImpl(MyServiceClient client) {
this.client = client;
}
#Override
public Data getData(String dataId) {//...}
Then in my Configuration class, I am creating a bean, but I need to pass it the MyServiceClient object in the constructor, and the catch is that I can't make MyServiceClient a bean because it's from external package and I can't modify it.
#Configuration
public class MyServiceProxyConfiguration {
#Bean(name = MyServiceProxy.BEAN_NAME)
public MyServiceProxy getMyServiceProxy(MyServiceClient client) { // could not autowire client
return new MyServiceProxyImpl(client);
}
}
So what I would like to do, is being able to pass/autowire an argument to getMyServiceProxy bean. Currently IntelliJ is giving me an error Could not autowire client. How can this be achieved?
UPDATE
Would something like the following work? Because IntelliJ is still reporting an "could not autowire" error. So if I created a bean method that returns the client I want injected, and then add #Inject annotation to the method where I want it injected.
public class MyServiceClientBuilder {
private final ClientBuilder builder;
public MyServiceClientBuilder(ClientBuilder builder) {
this.builder = builder;
}
#Bean
public MyServiceClient build() {
return builder.newClient();
}
#Configuration
public class MyServiceProxyConfiguration {
#Inject
#Bean(name = MyServiceProxy.BEAN_NAME)
public MyServiceProxy getMyServiceProxy(MyServiceClient client) { // could not autowire client
return new MyServiceProxyImpl(client);
}
}
You can define MyServiceClient as a separate bean in your configuration file like this:
#Configuration
public class MyServiceProxyConfiguration {
#Bean
public MyServiceClient getMyServiceClient () {
return MyServiceClient.getInstance(); //initiate MyServiceClient
}
#Bean(name = MyServiceProxy.BEAN_NAME)
public MyServiceProxy getMyServiceProxy(MyServiceClient client) {
return new MyServiceProxyImpl(client);
}
}
I have not tested this code, but it should work.

Spring 3.1 Java configuration and inner beans

#Bean
public TimedRepository timedRepository(RealRepository repo) {
return new TimedRepository(repo, timer); // Adds some metrics
}
#Bean
public RealRepository realRepository(DataSource ds) {
return new RealRepository(ds); // The real jdbc implementation
}
In the old XML days I would configure the real repository as an anonymous inner bean. Is it possible to do something similar with the new Java configuration approach? Instantiating the real repository inside the timedRepository factory method is not an option because I want Spring to pick up on annotations on RealRepository.
The motivation is to avoid any other beans to get hold of the real repository implementation. I should also mention that both beans implement a Repository interface that'll be used by any beans depending on the repository (they should not have to know about TimedRepository or RealRepository.
I dont think theres an equivalent to inner or local beans when using java based configuration. I'd probably try to create the RealRepository in the TimedRepositories bean method as well by asking for all dependencies in the method signature. But if you really need to have spring to take care of the RealRepository dependencies you need to use the bean factory.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader=AnnotationConfigContextLoader.class)
public class ConfigTest {
#Autowired TimedRepository timedRepo;
#Test
public void testRepository() {
Assert.assertNotNull(timedRepo);
}
#Configuration
static class TimedRepositoryConfiguration {
#Autowired
private AutowireCapableBeanFactory beanFactory;
#Bean
public TimedRepository timedRepository() {
RealRepository realRepository = (RealRepository) beanFactory.createBean(RealRepository.class, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, true);
return new TimedRepository(realRepository);
}
public RealRepository realRepository() {
return new RealRepository();
}
}
static class RealRepository {
}
static class TimedRepository {
private RealRepository realRepo;
public TimedRepository(RealRepository r) {
this.realRepo = r;
}
}
}
You can just instantiate the beans manually:
public class BeanThatDependsOnRealRepository() {
private final Repository repository;
#Inject
public BeanThatDependsOnRealRepository(DataSource dataSource) {
this.repository = new RealRepository(dataSource);
}
}
This is essentially what an anonymous inner bean does in XML. You've just explicitly constructed it and obtained its dependencies from Spring in the constructor of the enclosing class.
Late answer, but this is possible in Spring Core 4+ (and possibly Spring Core 3) with some trickery.
While standard Spring semantics do not support inner bean creation using JavaConfig, the internal functionality around inner beans can be taken advantage of to produce the same results.
Inner beans are produced during property value resolution by the BeanDefinitionValueResolver (see BeanDefinitionValueResolver#resolveValueIfNecessary). The concept of "inner beans" within Spring is primarily enclosed within this value resolver (which is the only producer of inner beans) and within bean factories under the term "contained beans" (from parent class DefaultSingletonBeanRegistry).
We can trick Spring into producing additional inner beans by defining a property as a BeanDefinition, according to the resolution strategy presented in BeanDefinitionValueResolver:
#Configuration
public class MyConfiguration {
private static Logger logger = LoggerFactory.getLogger(MyConfiguration.class);
private RealRepository realRepository;
private Timer timer;
public MyConfiguration(#SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") RealRepository realRepository, Timer timer) {
this.realRepository = realRepository;
this.timer = timer;
logger.info("Constructed MyConfiguration {}", this);
}
#Bean
public TimedRepository timedRepository() {
TimedRepository timedRepository = new TimedRepository(this.realRepository, this.timer);
logger.info("Created timed repo: {}", timedRepository);
return timedRepository;
}
public RealRepository realRepository(DataSource dataSource) {
RealRepository realRepository = new RealRepository(dataSource);
logger.info("Created real repo: {}", realRepository);
return realRepository;
}
#Override
public String toString() {
return "MyConfiguration{" +
"realRepository=" + realRepository +
", timer=" + timer +
'}';
}
}
#Component
public class InnerBeanInjectionBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
#Override
public int getOrder() {
// Preempt execution of org.springframework.context.annotation.ConfigurationClassPostProcessor
return 0;
}
#Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
String[] beanDefinitionNameList = ((ConfigurableListableBeanFactory) registry).getBeanNamesForType(MyConfiguration.class, true, false);
assert beanDefinitionNameList.length == 1;
BeanDefinition configurationBeanDefinition = registry.getBeanDefinition(beanDefinitionNameList[0]);
BeanDefinition realRepositoryBeanDefinition = BeanDefinitionBuilder.genericBeanDefinition(MyConfiguration.class)
.setScope(BeanDefinition.SCOPE_SINGLETON)
.setFactoryMethod("realRepository")
.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR)
.getBeanDefinition();
configurationBeanDefinition.getConstructorArgumentValues()
.addGenericArgumentValue(realRepositoryBeanDefinition);
}
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Do nothing
}
}
The obvious issue with this solution is that it requires manual processing through a BeanDefinitionRegistryPostProcessor, which is a lot of work for a small gain here. What I would suggest instead is the following:
Create a custom annotation (e.g., #InnerBean)
Attach this annotation to methods in #Configuration classes and candidate component classes where desired
Adapt the BeanDefinitionRegistryPostProcessor to scan classes for #InnerBean-annotated static methods (component-classes should be scanned in #postProcessBeanFactory and configuration classes in #postProcessBeanDefinitionRegistry)
Attach the bean definition to the containing bean definition's autowired constructor fields (or setter fields if that is your convention)
The following is an example:
#Target(ElementType.METHOD)
public #interface InnerBean {
}
#Configuration
public class MyConfiguration {
private static Logger logger = LoggerFactory.getLogger(MyConfiguration.class);
private RealRepository realRepository;
private Timer timer;
public MyConfiguration(#SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") RealRepository realRepository, Timer timer) {
this.realRepository = realRepository;
this.timer = timer;
logger.info("Constructed MyConfiguration {}", this);
}
#Bean
public TimedRepository timedRepository() {
TimedRepository timedRepository = new TimedRepository(this.realRepository, this.timer);
logger.info("Created timed repo: {}", timedRepository);
return timedRepository;
}
#InnerBean
public static RealRepository realRepository(DataSource dataSource) {
RealRepository realRepository = new RealRepository(dataSource);
logger.info("Created real repo: {}", realRepository);
return realRepository;
}
#Override
public String toString() {
return "MyConfiguration{" +
"realRepository=" + realRepository +
", timer=" + timer +
'}';
}
}
#Component
public class InnerBeanInjectionBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
private static Logger logger = LoggerFactory.getLogger(InnerBeanInjectionBeanFactoryPostProcessor.class);
private Set<BeanDefinition> processedBeanDefinitionSet = new HashSet<>();
#Override
public int getOrder() {
// Preempt execution of org.springframework.context.annotation.ConfigurationClassPostProcessor
return 0;
}
#Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
ConfigurableListableBeanFactory beanFactory = (ConfigurableListableBeanFactory) registry;
String[] configBeanDefinitionNames = beanFactory.getBeanNamesForAnnotation(Configuration.class);
Arrays.stream(configBeanDefinitionNames)
.map(beanFactory::getBeanDefinition)
.filter(this::isCandidateBean)
.peek(this.processedBeanDefinitionSet::add)
.forEach(this::autowireInnerBeans);
}
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
Arrays.stream(beanFactory.getBeanDefinitionNames())
.map(beanFactory::getBeanDefinition)
.filter(this::isCandidateBean)
.filter(beanDefinition -> !this.processedBeanDefinitionSet.contains(beanDefinition))
.forEach(this::autowireInnerBeans);
}
private boolean isCandidateBean(BeanDefinition beanDefinition) {
return beanDefinition.getBeanClassName() != null && beanDefinition.getBeanClassName().startsWith("com.example.demo.");
}
private void autowireInnerBeans(BeanDefinition beanDefinition) {
// Get #InnerBean methods
assert beanDefinition instanceof AnnotatedBeanDefinition;
AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDefinition;
Set<MethodMetadata> innerBeanMethods = annotatedBeanDefinition.getMetadata().getAnnotatedMethods(InnerBean.class.getName());
// Attach inner beans as constructor parameters
for (MethodMetadata method : innerBeanMethods) {
String innerBeanName = method.getMethodName();
if (!method.isStatic()) {
logger.error("#InnerBean definition [{}] is non-static. Inner beans must be defined using static factory methods.", innerBeanName);
continue;
}
BeanDefinition innerBeanDefinition = BeanDefinitionBuilder.genericBeanDefinition(beanDefinition.getBeanClassName())
.setScope(BeanDefinition.SCOPE_SINGLETON)
.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR)
.setFactoryMethod(innerBeanName)
.getBeanDefinition();
beanDefinition.getConstructorArgumentValues()
.addGenericArgumentValue(new ConstructorArgumentValues.ValueHolder(innerBeanDefinition, method.getReturnTypeName(), method.getMethodName()));
}
}
}
There will be a few benefits and caveats of doing this. One large benefit is that the bean lifecycle will be managed by the Spring IoC container, meaning that lifecycle callbacks (such as #PostConstruct and #PreDestroy) will be called. The bean can be automatically managed according to the lifecycle of the parent. Caveats include that the beans cannot be injected as factory-method parameters (although with a bit of work you might able to fix this) and that AOP proxying will not be applied to these methods within #Configuration classes (i.e., realRepository() should never be called as it will not reference the singleton inner bean -- instead, the instance field should always be referenced). Further proxying (similar to ConfigurationClassEnhancer.BeanMethodInterceptor) would need to be added in order to apply this.

Categories

Resources