Guice Inject Field in class NullPointerException, circular dependency issue introduced - java

I need to use create a singleton in Guice defined in separate library.
#RequiredArgsConstructor
public class Operator {
#NonNull private final Catalog catalog;
#Inject private Evaluator evaluator;
...
}
One of the problem is that this class introduces circular dependency, Evaluator -> Operator -> Evaluator. I know it is not a good design, but is consumed by other packages, there is no easy way to change it. This library has the beans created using Spring framework, where this circular dependency could be handled.
Now I need to create an instance of the Operator in a service based on Guice, I have created the singleton Evaluator in the service, but it was not able to inject the singleton into the Operator.
#Provides #Singleton
public Operator operator(final Catalog catalog)
{
return new Operator(catalog);
}
#Provides #Singleton
public Evaluator evaluator(final Operator operator) {
return new Evaluator(operator);
}
Since the Operator class is being used for other services based on Spring framework, I would prefer not to change it. What can I do to make the Guice able to inject the Evaluator into Operator?
Thanks in advance for any help!

Try this, I hope it will help you.
public class Evaluator {
#Inject public Evaluator(Operator op) {
// ...
}
}
public class Operator {
#Inject public Operator(map m) {
// ...
}
}
public class map {
#Inject public map(Provider<Evaluator> EvaluatorProvider) {
// ...
}
}

In this circular dependency case, Guice is not smart enough to help injecting dependencies, you can specifically ask Guice to inject dependencies for this class.
#Provides #Singleton
public Operator operator(final Catalog catalog)
{
return new Operator(catalog);
}
And then injector.injectMembers(injector.getInstance(Operator.class)) would help inject the required dependencies.

Related

How can I create multiple Spring beans in a #Bean-annotated method or anything similar?

In a Spring application that uses HTTP remoting, I have a service façade module configured as follows (I made the code generic to improve clarity):
#Configuration
public class MyFacadeConfig {
private HttpInvokerServiceExporter facade(Class<?> cls) {
HttpInvokerServiceExporter bean = new HttpInvokerServiceExporter();
// The service referred to by this exporter is already instantiated as another Spring bean with all its dependencies.
bean.setService(appContext.getBean(cls));
bean.setServiceInterface(cls);
return bean;
}
#Bean("/first.service")
public HttpInvokerServiceExporter firstServiceFacade() {
return facade(FirstService.class);
}
#Bean("/second.service")
public HttpInvokerServiceExporter secondServiceFacade() {
return facade(SecondService.class);
}
// ... and so on for the 37 other services
}
where FirstService and SecondService are interfaces with existing implementations whose detail is not needed here.
I have another module that defines 39 proxies (instances of HttpInvokerProxyFactoryBean) corresponding to each of my services exposed through my façade.
So far, everything works properly.
But I would like to make the code more generic, elegant, and robust while mitigating the risk of error (e.g., a bad mapping between a service and its proxy in the future). The way I would like to do this is as follows:
First, I move the façade/proxy metadata into an enumeration:
public enum ConfigBeansFacade {
FIRST("/first", FirstService.class),
SECOND("/second", SecondService.class)
// ... and so on for the 37 other services
;
private String beanName;
private Class<?> serviceInterface;
// Constructor and getters
public String getCompleteBeanName() {
return beanName + ".service";
}
}
Then the configuration of the façade would be simplified in a style similar to the following:
#Configuration
public class MyFacadeConfig {
#Autowired
private ConfigurableBeanFactory beanFactory;
#Autowired
public void configExporters() {
for (ConfigBeansFacade bean : ConfigBeansFacade.values()) {
HttpInvokerServiceExporter exp = new HttpInvokerServiceExporter();
exp.setService(beanFactory.getBean(bean.getServiceInterface()));
exp.setServiceInterface(bean.getServiceInterface());
beanFactory.registerSingleton(bean.getCompleteBeanName(), exp);
}
}
}
I tried every single recipe I found in online forums, including StackOverflow, but there are two constraints not met elsewhere:
When defining the exporters, the underlying services are other Spring beans that are instantiated, initialized, and registered with their own configuration and dependencies through the standard Spring mechanics. There is no direct class instantiation other than the exporters themselves.
I thought about grouping the exporters into a single collection as suggested by some people. The only problem is that Spring MVC uses the HttpInvokerServiceExporter Spring bean names as endpoint URIs when registering the exporters into its own configuration. I must therefore register each exporter as a “first-class citizen” bean with its own bean name into the application context.
Given these constraints, the problem I have arises in (1) when I try to retrieve the underlying services to be encapsulated into exporters: they are not necessarily ready yet, which results into UnsatisfiedDependencyExceptions.
I tried solutions with a #PostContruct-annotated method, with a BeanPostProcessor, with an #Autowired method (as shown above), nothing is working as required.
Does anyone know about a way or a technique to initialize and register multiple beans inside a single method under my constraints described above? Such a method doesn't need to be annotated with #Bean, #Autowired, or any other specific annotation, it's just an example of what I tried.
In the client module, mercifully, the HttpInvokerProxyFactoryBean instances need only the interfaces and the bean names, so constraint (1) above should not apply.
Thanks in advance for any help you can provide...
I'm not 100% I've understood what you're trying to do but I wonder if you could try autowiring a List of beans that implement an interface?
e.g.
public interface MyService {
String getKey();
void doStuff();
}
Then implement as many of these as you require
e.g.
#Component
public class FirstService implements MyService {
public String getKey() {
return "/first";
}
public void doStuff() {
...
}
}
then have a factory bean with the autowired list
#Component
public class MyServiceFactory {
private final List<MyService> services;
#Autowired
public MyServiceFactory(List<MyService> services) {
this.services = services;
}
}
To add more implementations of MyService, simply add them as #Component and Spring magically picks them up and adds them to the list.
Sometimes I find it useful to access my implementations via a Map
#Component
public class MyServiceFactory {
private final Map<String, MyService> services;
#Autowired
public MyServiceFactory(List<MyService> services) {
this.services = services
.stream()
.collect(toMap(MyService::getKey, Function.identity()));
}
public MyService getServiceByKey(String key) {
return services.get(key);
}
}
I find this keeps each implementation nice and self contained (and easy to test). Spring automatically picks up all the components that implement my interface without the factory having a huge number of imports. And I can test the factory easily by mocking the list of implementations.

Should I never use #PostConstruct in Spring Boot when I have All Args Constructor?

In out project we don't use setter or filed injection, we use only constructor injection, and I know that both options 1. and 2. may work.
Is it unsafe to work with beans in constructor in that case?
Or spring boot 2+ makes something, and I should better use option 1. instead of 2. I can't imagine case when option 1 will go wrong
#Component
#ConfigurationProperties("config")
public class ServiceConfigProperties {
// .... some code
}
Can be unsafe? - but it looks better
#Component
public class Service {
private boolean skipCheck;
public Service(ServiceConfigProperties configProps) {
this.skipCheck = configProps.isSkipCheck();
}
}
Can't be unsafe?
#Component
public class Service {
private boolean skipCheck;
private ServiceConfigProperties configProps;
public Service(ServiceConfigProperties configProps) {
this.configProps= configProps;
}
#PostConstruct
public void initConfig() {
this.skipCheck= configProps.isSkipCheck();
}
}
With a couple of caveats, interacting with constructor-injected beans inside the constructor is completely safe.

Can we have a factory class as spring bean and have a factory method returning multiple spring beans based on the condition?

I want to return multiple spring beans based on the condition in the factory class.
Is this a good practice?
Any better ways to write the following piece of code?.
Any other design patterns suitable here?
Below is the code snippet:
package com.test;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
#Component
public class InstanceFactory {
#Resource(name = "instance1")
private Instance instance1;
#Resource(name = "instance2")
private Instance instance2;
public Instance getService(Condition condition) {
if (condition.one() && condition.two()) {
return instance2;
} else {
return instance1;
}
}
}
It depends on what you want to achieve. Factory Pattern is meant to create objects but what you are returning are objects already create somewhere else (Spring in this case). If you want to create beans that will be managed by Spring there are several ways:
#Conditional(YourConditionImplementation.class): This annotation added on a method of a #Configuration annotated class will allow you to create a bean when the given condition is fullfilled. Example here: https://javapapers.com/spring/spring-conditional-annotation/
You can uses as well BeanFactory to inject the definition of your bean (DefinitionBean) into the container. Example here: https://www.logicbig.com/tutorials/spring-framework/spring-core/bean-definition.html
Now, if you want an object that determine what object of type Instance fits better for some need then your approach is ok, but it is not technically a factory :)
When designing something like that I would face that solution considering two design patterns:
Strategy pattern: In order to replace repetitive if else every time you need to evaluate more instances.
Decorator pattern: Trying to make every condition as configurable as possible. They can be composed (decorated) for one or more predicates.
Considering these two pattens you might achieve something like this:
First, define which conditions will identify a given instance:
public enum InstanceType {
INSTANCE_TYPE_1(Condition::isOne, Condition::isTwo),
INSTANCE_TYPE_2(Condition::isOne, Condition::isThree),
...;
private List<Predicate<Condition>> evaluators;
#SafeVarargs
InstanceType(final Predicate<Condition>... evaluators) {
this.evaluators = Arrays.asList(evaluators);
}
public boolean evaluate(final Condition condition) {
return evaluators.stream().allMatch(it -> it.test(condition));
}
}
Then, you should link every instance implementation to an specific instance type:
#Component
public class InstanceOne implements Instance {
#Override
public InstanceType getType() {
return InstanceType.INSTANCE_TYPE_1;
}
}
Finally, a class to config where defining the relation between types and instances as EnumMap
#Configuration
public class InstanceFactoryConfig {
#Autowired
private List<Instance> instances;
#Bean
public EnumMap<InstanceType, Instance> instancesMap() {
EnumMap<InstanceType, Instance> instanceEnumMap = new EnumMap<>(InstanceType.class);
instances.forEach(i -> instanceEnumMap.put(i.getType(), i));
return instanceEnumMap;
}
}
Thus, you InstanceFactory can be replaced to something like this:
public class InstanceFactory {
#Autowire
private final EnumMap<InstanceType, Instance> instancesMap;
public void getInstance(Condition condition) {
instancesMap.get(getInstanceType(condition)).doSomething();
}
private InstanceType getInstanceType(Condition condition) {
return Arrays.stream(InstancesType.values())
.filter(evaluator -> evaluator.evaluate(condition))
.findFirst().orElseThrow(() -> new RuntimeException("Instance type not found"));
}
}
As you can see, you InstanceFactory is less prone to be modified. This means, every time you need you add a new instance implementation you only need to modify the InstanceType enum. Hope this is helps.
You can use spring existing FactoryBean interface and implement your own logic
It’s one of the best approaches to create beans in spring framework
Here is the link with example :
https://www.baeldung.com/spring-factorybean
See:
Spring Profile
The active profile is set by properties and based on the value you assign to the profile, Spring will load different beans for the same interface.
So it might be exactly what you need.

how to use guice injector in a guice provider?

I'm using guice to inject dependencies.
I have this provider:
public class RequestUrlRepository implements Provider<IRequestUrlRepository> {
#Singleton
#Override
public IRequestUrlRepository get() {
IRequestUrlRepository answer = null;
if (System.getProperty("").equals(RouteOrCostRequest.cost.toString())){
answer = new CostRequestUrlRepository(...);
}
else
{
answer = new RoutingRequestUrlRepository(...);
}
return answer;
}
}
how can I use guice injector to fill new CostRequestUrlRepository(...); and new RoutingRequestUrlRepository(...) when it's in a provider?
If not possible, how can I init them without manually creating all the ctor's params?
Providers can accept #Inject-annotated constructors and fields, and Guice's built-in bindings will let you inject both Injector and a Provider for any key the injector can provide (e.g. Provider<CostRequestUrlRepository>).
#Singleton
public class RequestUrlRepository implements Provider<IRequestUrlRepository> {
#Inject Provider<CostRequestUrlRepository> costRepositoryProvider;
#Inject Provider<RoutingRequestUrlRepository> routingRepositoryProvider;
#Inject Injector injector;
#Override public IRequestUrlRepository get() {
IRequestUrlRepository answer = null;
if (System.getProperty("").equals(RouteOrCostRequest.cost.toString())){
return costRepositoryProvider.get();
} else {
return routingRepositoryProvider.get();
}
// Alternatively:
return injector.getInstance(Class.forName(System.getProperty("")));
}
}
Note that the #Singleton annotation goes on the class, not the method; per the Guice mailing list "Scope annotations apply to providers as a whole, annotating the get() method with #Singleton is erroneous and ignored." (link).
Ideally, rather than injecting the entire injector, you should inject each provider; this should make it easier to see your system's dependencies, and then you're relying less on Guice and more on the general JSR330 annotations. However, if you have to instantiate an arbitrary class based on a name or Class literal in a variable, then injecting the Injector is the way to go.

Custom injection with standard annotations

Is it possible to perform custom injection with constructor/factory arguments computed based on injection point WITHOUT defining custom annotation ?
Given a code:
class Foo {
public Foo() {}
public Foo(java.lang.reflect.Field field) {}
}
class Bar {
#javax.inject.Inject Foo foo;
}
How can I configure guice to use second constructor of Foo (passing target field) without modifying Bar.
I know that guice can do custom injections of java.util.logging.Logger with standard #Inject but that seems hardcoded and uses internal api.
You can use injection providers to do it. See https://code.google.com/p/google-guice/wiki/ProviderBindings and https://code.google.com/p/google-guice/wiki/ProvidesMethods. You just have to tell Guice how to instantiate the object when it binds it.
For exemple in a project of mine I tried this :
public static class CalendarServiceProvider implements Provider<CalendarService> {
#Inject
GAppsOAuth oauth;
private GCalendarService service;
#Override
public CalendarService get() {
if (service == null) {
service = new GCalendarService(oauth);
}
return service;
}
}
I don't know if it's what you're looking for, but I hope it'll help.
If you want only to use specific constructor, you can use constructor bindings:
bind(Foo.class).toConstructor(Foo.class.getConstructor(java.lang.reflect.Field.class));
If you need something more complex, you have to use custom injections.

Categories

Resources