I downloaded intelliJ which gives me an advice to put my injections in a constructor. However when doing what they advice I have an other advice message telling me I need an empty constructor. So I'm wondering what's the best way to implement something like this :
That is just a background task in a jsf application that run every minute.
#Singleton
public class MatchesBgService implements Serializable {
#Inject //intelliJmessage : Hey, you should use constructor injection
private MatchLookup ml;
#Inject
private MatchTask bgTask;
public MatchesBgService(){
comparator = new MatchComparator();
}
#Schedule(hour = "*", minute = "*/1", second = "20", persistent = false)
public void gettingMatches() {
Your code might look like this:
#Singleton
public class MatchesBgService implements Serializable {
private final MatchLookup ml;
private final MatchTask bgTask;
#Inject
public MatchesBgService(MatchLookup ml, MatchTask bgTask){
this.ml = ml;
this.bgTask = bgTask;
// ...
}
}
Answering your doubts:
It's considered a good practice to use a constructor injection wherever it makes sense.
CDI spec says you need a default empty constructor (to have class proxyable).
But fortunately, at least Weld doesn't require it - so my above code will
work just fine.
That is why IntelliJ gives you these advices.
Cheers
Related
My ExampleBean needs information from UsefulBean1 only at creation time. So I can discard the UsefulBean1 instance after getting the information I want.
#ManagedBean
public class ExampleBean {
private int value;
#Inject
public void setUseful(UsefulBean usefulBean){
this.value = usefulBean.getValue();
//bye, bye usefulBean. see ya.
}
}
But what about my ExampleBean2, that needs, at creation time, combined information from UsefulBean1and UsefulBean2?
I know I can get them #Injected and combine the information on a #PostConstruct method:
#ManagedBean
public class ExampleBean2 {
private int value;
#Inject
private UsefulBean1 usefulBean1;
#Inject
private UsefulBean2 usefulBean2;
#PostConstruct
public void init(){
this.value = this.usefulBean1.getValue() + this.usefulBean2.getValue();
//from this point on, the usefulBeans fields are useless...
this.usefulBean1 = null;
this.usefulBean2 = null;
}
}
But it annoys me a bit that I keep these two no-longer-necessary fields (this.usefulBean1 and this.usefulBean2).
I have tried a multi-parameter set method, to no avail.
This is surely nothing breaking anything or wasting resources. But the code, IMHO, would just be more clear without fields working as temporary throwaway variables.
Is there a away to initialize a CDI bean with data from multiple other beans, without the need to set them as fields?
(First, #ManagedBean has nothing to do with CDI. It should not be used.)
(Second, always think about lifespans ("scopes"): how long should each bean live? For this example I'll pretend that you want ExampleBean2 to be the only such bean in your application, so I'll mark it with #ApplicationScoped (some of your comments above reference proxying so this is a reasonable guess). You could annotate it with, for example, #RequestScoped or #Dependent or some other scope instead. If you don't annotate it with any scope annotation, then it will behave exactly as if you had annotated it with #Dependent.)
Like this:
#ApplicationScoped
public class ExampleBean2 {
private final int value;
/**
* #deprecated To be used only by the CDI framework, not end users.
*/
#Deprecated
protected ExampleBean2() {
super();
}
#Inject
public ExampleBean2(final UsefulBean1 usefulBean1, final UsefulBean2 usefulBean2) {
super();
this.value = this.usefulBean1.getValue() + this.usefulBean2.getValue();
}
}
I have a class which is used as a common class in my project. That class has the access to some other core classes which were inject in that class, through which I can call some APIs. So when I need to call an API in a class, I usually Inject this common class and use the specific API. But when I inject the common class in many other classes, all the core classes also get injected even I need to use one or two of that core classes.
This is my common class
public class ApiService {
private StuResource stuResource;
private VendResource vendResource;
private EduResource eduResource;
private RKEResource rKEResource;
private AleResource aleResource;
private GloResource gloResource;
#Inject
public ApiService(StuResource stuResource, VendResource vendResource,
EduResource eduResource, RKEResource rKEResource,
AleResource aleResource, GloResource gloResource) {
this.stuResource = stuResource;
this.vendResource = vendResource;
this.eduResource = eduResource;
this.rKEResource = rKEResource;
this.aleResource = aleResource;
this.gloResource = gloResource;
}
{Methods for call APIs}
}
So I plan to use singleton patter, so that I can create an object of the common class one time and can use that object everywhere in other classes.
Help me in this implementation. How can I implement singleton pattern in this situation.
It's bad idea at all - put all functionality in single place.
Create separate services for each business process, give them required resources only. I.e.
#Component
public class SchoolService {
private StuResource stuResource;
private EduResource eduResource;
private GloResource gloResource;
#Inject
public SchoolService(StuResource stuResource, EduResource eduResource, GloResource gloResource) {
this.stuResource = stuResource;
this.eduResource = eduResource;
this.gloResource = gloResource;
}
{Methods for call APIs}
}
then
#Component
public class PayService {
private VendResource vendResource;
private EduResource eduResource;
#Inject
public ApiService(VendResource vendResource, EduResource eduResource) {
this.vendResource = vendResource;
this.eduResource = eduResource;
}
{Methods for call APIs}
}
and so on.
Each of these classes will be singletons as you want.
My current situation:
I want to inject the following class into my application:
public interface IConfigAccessor<T extends IConfig> {
...
}
ConfigAccessors are a proxy-objects, created dynamically at runtime. The creation of these object works as follows:
public class ConfigFactory implements IConfigFactory {
private final IConfigUpdater updater;
#Inject
public ConfigFactory(IConfigUpdater updater) {
this.updater = updater;
}
#Override
public <T extends IConfig> IConfigAccessor<T> register(final String configKey, final Class<T> configClass) {
ConfigCache<T> configCache = new ConfigCache<>(new SomeOtherThings(), configKey, configClass);
updater.register(configCache);
return new ConfigAccessor<>(configCache, configKey, configClass);
}
}
As you can see, to create these objects, I need to inject the ConfigUpdater and other depdencies. This means, that guice needs to be fully configured already.
To get the instance out of Guice, I use the following code:
IConfigFactory configClient = injector.getInstance(IConfigFactory.class);
IConfigAccessor<ConcreteConfig> accessor = configClient.register("key", ConcreteConfig.class)
How I want to inject them via Guice:
Currently, I can get the requried objects, but I have to manually pass them around in my application.
Instead, what I want to have is the following:
public class SomeClass {
#Inject
public SomeClass(#Config(configKey="key") IConfigAccessor<ConcreteConfig> accessor) {
// hurray!
}
}
What's the correct approach/technology to get this working?
After a lot of research, I'm feeling a bit lost on how to approach this topic. There are a lot of different things Guice offers, including simple Providers, custom Listeners which scan classes and identify custom annotations, FactoryModuleBuilders and more.
My problem is quite specific, and I'm not sure which of these things to use and how to get it working. I'm not even sure if this is even possible with Guice?
Edit: What I have so far
I have the following annotation which I want to use inside constructor paramters:
#Target({ ElementType.FIELD, ElementType.PARAMETER })
#Retention(RetentionPolicy.RUNTIME)
public #interface InjectConfig {
String configKey();
}
Inside the module, I can bind a provider to IConfigAccessor (with the above annotation) as such:
bind(IConfigAccessor.class).annotatedWith(InjectConfig.class)
.toProvider(new ConfigProvider<>());
However, there are two problems whith this:
The provider cannot provide IConfigAccessor. To create such an instance, the provider would need an IConfigUpdater, but since I use 'new' for the provider, I can't inject it.
Inside the provider, there is no way to find out about the configKey used in the Annotation.
Second approach:
Let's assume that I already know all configurations and configKeys I want to inject during startup. In this case, I could loop over all possible configKeys and have the following binding:
String configKey = "some key";
final Class<? extends IConfig> configClass =...;
bind(IConfigAccessor.class).annotatedWith(Names.named(configKey))
.toProvider(new ConfigProvider<>(configKey, configClass));
However, problem (1) still resides: The provider cannot get an IConfigUpdater instance.
The main problem here is that you cannot use the value of the annotation in the injection. There is another question which covers this part:
Guice inject based on annotation value
Instead of binding a provider instance, you should bind the provider class, and get the class by injecting a typeliteral.
That way, your config factory can look like that:
public class ConfigFactory<T extends IConfig> implements IConfigFactory {
#Inject private final IConfigUpdater updater;
#Inject private TypeLiteral<T> type;
#Override
public IConfigAccessor<T> register(final String configKey) {
Class<T> configClass = (Class<T>)type.getRawType();
ConfigCache<T> configCache = new ConfigCache<>(new SomeOtherThings(), configKey, configClass);
updater.register(configCache);
return new ConfigAccessor<>(configCache, configKey, configClass);
}
}
And then SomeClass:
public class SomeClass {
#Inject
public SomeClass(ConfigFactory<ConcreteConfig> accessor) {
ConcreteConfig config = accessor.register("key");
}
}
Since SomeClass needs to know "key" anyway, this is not too much a change information-wise. The downside is that the SomeClass API now gets a factory instead of the concrete config.
[EDIT]
And here is someone who actually did inject annotated values using custom injection.
Is it bad practice to use dependency injection in factory classes? Should I let the users of my framework take care of dependency injection? Should I use approach A or approach B?
SomeUserClass
package com.impl;
#Service
public class SomeUserClass {
#Autowired
private SMSActionFactoryService actionFactoryService:
#Autowired
private PropertyManager properties;
public void doStuff(){
// approach A
SMSAction action = actionFactoryService.createAction("hello");
// approach B
action = SMSActionFactory.createAction(properties, "hello");
// the user should never call Action::doAction.
// It gets called by the framework on a condition.
scheduler.addAction(State.ERROR, action)
}
}
SMSAction
package com.framework;
public class SMSAction extends Action {
public SMSAction(PropertyManager properties, String message){
}
public void doAction(){
}
}
SMSActionFactoryService
package com.framework;
#Service
public class SMSActionFactoryService {
#Autowired
private PropertyManager properties;
public SMSActionFactory createAction(String message) {
return new SMSActionFactoryService(properties, message);
}
}
SMSActionFactory
package com.framework;
public class SMSActionFactory {
public static SMSActionFactory createAction(PropertyManager properties, String message) {
return new SMSActionFactory(properties, message);
}
}
I think you have a context problem, so the answer depends on the context. But I'll give some of my experience, and not a formal (and irrefutable) answer. Based on the title of the answer (practices) I'll give you what I call good practices tips that helped me a lot when I started Spring development.
First of all, let's think about the Dependency Injection you have. You're wiring a field, and we know that the Spring team used to suggest us to use constructor based injection (and assertions for all mandatory dependency) as you can see here. Well, I know it was a problem with the tests framework that couldn't wire the dependencies in an easy way, but now they can. But there's another advantage using this pattern, you can make your bean field final. Another advantage is that you prevent circular dependencies, like X depends on Y and Y depends on X and so on. So, as the first tip, I would suggest you to use something like:
private final SMSActionFactoryService actionFactoryService:
private final PropertyManager properties;
#Autowired
public SomeUserClass(SMSActionFactoryService actionFactoryService,
PropertyManager properties) {
Assert.notNull(actionFactoryService, "The actionFactoryService bean is null, you should provide the bean to run this application");
Assert.notNull(properties, "The properties bean is null, you should provide the bean to run this application");
this.actionFactoryService = actionFactoryService;
this.properties = properties;
}
This way you prevent any other code part to change the field value. As you can see in Spring autowiring setter/constructor PROs and CONs this is a preference subject.
Now, for the second tip, I wouldn't use #Service for a factory, not even #Component because factories needs to be open for extension and close for modification. You're going to understand better if take a look here.
That said friend, I suggest you to embrace approach B.
I am trying to define a custom DeltaSpike ConfigSource. The custom config source will have the highest priority and check the database for the config parameter.
I have a ConfigParameter entity, that simply has a key and a value.
#Entity
#Cacheable
public class ConfigParameter ... {
private String key;
private String value;
}
I have a #Dependent DAO that finds all config parameters.
What I am trying to do now, is define a custom ConfigSource, that is able to get the config parameter from the database. Therefore, I want to inject my DAO in the ConfigSource. So basically something like
#ApplicationScoped
public class DatabaseConfigSource implements ConfigSource {
#Inject
private ConfigParameterDao configParameterDao;
....
}
However, when registering the ConfigSource via META-INF/services/org.apache.deltaspike.core.spi.config.ConfigSource, the class will be instantiated and CDI will not work.
Is there any way to get CDI working in this case?
Thanks in advance, if you need any further information, please let me know.
The main problem is, that the ConfigSource gets instantiated very early on when the BeanManager is not available yet. Even the JNDI lookup does not work at that point in time. Thus, I need to delay the injection/lookup.
What I did now, is add a static boolean to my config source, that I set manually. We have a InitializerService that makes sure that the system is setup properly. At the end of the initialization process, I call allowInitialization() in order to tell the config source, that the bean is injectable now. Next time the ConfigSource is asked, it will be able to inject the bean using BeanProvider.injectFields.
public class DatabaseConfigSource implements ConfigSource {
private static boolean allowInit;
#Inject
private ConfigParameterProvider configParameterProvider;
#Override
public int getOrdinal() {
return 500;
}
#Override
public String getPropertyValue(String key) {
initIfNecessary();
if (configParameterProvider == null) {
return null;
}
return configParameterProvider.getProperty(key);
}
public static void allowInitialization() {
allowInit = true;
}
private void initIfNecessary() {
if (allowInit) {
BeanProvider.injectFields(this);
}
}
}
I have a request-scoped bean that holds all my config variables for type-safe access.
#RequestScoped
public class Configuration {
#Inject
#ConfigProperty(name = "myProperty")
private String myProperty;
#Inject
#ConfigProperty(name = "myProperty2")
private String myProperty2;
....
}
When injecting the Configuration class in a different bean, each ConfigProperty will be resolved. Since my custom DatabaseConfigSource has the highest ordinal (500), it will be used for property resolution first. If the property is not found, it will delegate the resolution to the next ConfigSource.
For each ConfigProperty the getPropertyValue function from the DatabaseConfigSource is called. Since I do not want to retreive the parameters from the database for each config property, I moved the config property resolution to a request-scoped bean.
#RequestScoped
public class ConfigParameterProvider {
#Inject
private ConfigParameterDao configParameterDao;
private Map<String, String> configParameters = new HashMap<>();
#PostConstruct
public void init() {
List<ConfigParameter> configParams = configParameterDao.findAll();
configParameters = configParams.stream()
.collect(toMap(ConfigParameter::getId, ConfigParameter::getValue));
}
public String getProperty(String key) {
return configParameters.get(key);
}
}
I could sure change the request-scoped ConfigParameterProvider to ApplicationScoped. However, we have a multi-tenant setup and the parameters need to be resolved per request.
As you can see, this is a bit hacky, because we need to explicitly tell the ConfigSource, when it is allowed to be instantiated properly (inject the bean).
I would prefer a standarized solution from DeltaSpike for using CDI in a ConfigSource. If you have any idea on how to properly realise this, please let me know.
Even though this post has been answered already I'd like to suggest another possible solution for this problem.
I managed to load properties from my db service by creating an #Signleton #Startup EJB which extends the org.apache.deltaspike.core.impl.config.BaseConfigSource and injects my DAO as delegate which I then registered into the org.apache.deltaspike.core.api.config.ConfigResolver.
#Startup
#Singleton
public class DatabaseConfigSourceBean extends BaseConfigSource {
private static final Logger logger = LoggerFactory.getLogger(DatabaseConfigSourceBean.class);
private #Inject PropertyService delegateService;
#PostConstruct
public void onStartup() {
ConfigResolver.addConfigSources(Collections.singletonList(this));
logger.info("Registered the DatabaseConfigSourceBean in the ConfigSourceProvider ...");
}
#Override
public Map<String, String> getProperties() {
return delegateService.getProperties();
}
#Override
public String getPropertyValue(String key) {
return delegateService.getPropertyValue(key);
}
#Override
public String getConfigName() {
return DatabaseConfigSourceBean.class.getSimpleName();
}
#Override
public boolean isScannable() {
return true;
}
}
I know that creating an EJB for this purpose basically produces a way too big overhead, but I think it's a bit of a cleaner solution instead of handling this problem by some marker booleans with static accessors ...
DS is using the java se spi mechanism for this which is not CD'Injectable'. One solution would be to use the BeanProvider to get hold of your DatabaseConfigSource and delegate operations to it.