#Named("myUniqueName")
public class ReportDashboardDao implements DashboardDAO{
//STUFF
}
how can i access the string inside #Named tag when i am injecting DashboardDAO like this :
#Named
public class DshboardDaoConsumer(){
#Inject List<DashboardDAO> dashboardDAO;
//STUFF
}
Use a Map instead
#Inject
Map<String, DashboardDao> dashBoardDaos;
This will inject a Map with bean names as keys and daos as values.
Of course, you could also read the annotation value from class instances.
You can't. You're injecting by type. After injection has been done, Spring does not leave behind any relation between the bean's object and the bean's name.
You might want to check out ApplicationContext#getBeanNamesByType() depending on what you want to do.
By implementing BeanNameAware.
#Named("myUniqueName")
public class ReportDashboardDao implements DashboardDAO, BeanNameAware{
//STUFF
private String beanName;
#Override
public Void setBeanName(String beanName) {
this.beanName = beanName;
}
}
So that Spring can inject the beanName into the bean. If you add a public String getBeanName(); in your DashboardDAO interface, DashboardDaoConsumer will be able to obtain it.
In this particular case, Spring will inject the name you specified in the annotation.
Related
I'm trying to pass parameter to one of constructor of my BBFilter component, however it throws the exception that No beans of String type found. I have autowired the constructor as well. Am I doing anything wrong? Please advise
#Bean
public MyBean bbFilter() {
BBBean bbBean = new BBBean();
bbBean.setFilter(new BBFilter("plan1"));
}
BBFilter
#Component
public class BBFilter implements Filter {
private String planType;
#Autowired
public BBFilter(String planType) { --> Could not autowire. No beans of String type found
this.planType = planType;
}
}
I am assuming you are using Spring. The #Component annotation tells spring to automatically create an Instance of BBFilter as a Bean.
You also annotated the constructor with #Autowired. So Spring searches it's beans for fitting types and injects the automatically on construction. Since you probably didn't define any String bean it cannot autowire the String and throws an exception.
But since you want to create the Filter manually anyways you can simply remove both annotations from your BBFilter Class:
public class BBFilter implements Filter {
private String planType;
public BBFilter(String planType) {
this.planType = planType;
}
}
This should fix the exception but you also can no longer inject it anywhere else (per #Autowire) if needed.
Declare bean of BBFilter like
#Bean
public BBFilter bbFilter() {
return new BBFilter("plan1");
}
And use it in BBBean like this
#Bean
public MyBean bbFilter() {
BBBean bbBean = new BBBean();
bbBean.setFilter(bbFilter());
}
And remove #Component and #Autowired from BBFilter
I'm using spring and want to implement some java-configuration in my application.
Here is spring's abstract config, for example
#Configuration
class AbstactConfiguration {
protected void configureSettings(Builder builder) {}
}
And my implementation
I want to setup some injected collection in configureSettings method, so I've done field injection to configuration class, since I can't add this field as argument to override method
class ConfigurationImpl extends AbstactConfiguration {
#Autowired(required = false)
Collection<Something> collection;
#Override
protected void configureSettings(Builder builder) {
builder.addCollection(collection)
}
}
Am I doing it right? Because I got warning: Field injection is not recommended
You should create a constructor of ConfigurationImpl and it must has "Collection<>" as an input. So you can inject bean from another class.
I would like to have a singleton bean instance by generic parameter based on a single #Component generic class.
(I am using Spring 4.)
My code :
I have an interface like this :
public interface Mapper<I, O> {
...
}
And multiple implementation of it which are Spring #Components (singletons). Something like this :
#Component
public class MapperA implements Mapper<ClazzAI, ClazzAO> {
...
}
and
#Component
public class MapperB implements Mapper<ClazzBI, ClazzBO> {
...
}
where ClazzAI, ClazzAO, ClazzBI and ClazzBO are basic Java classes.
I have another Spring #Component (singleton) which have a Mapper class as a generic parameter :
#Component
public class TransformerImpl<I, O, M extends Mapper<I, O>> {
/** The Mapper */
protected final M mapper;
#Inject
private TransformerImpl(final M mapper) {
this.mapper= mapper;
}
...
}
and I would like to use it like this :
#Inject
private TransformerImpl<ClazzAI, ClazzAO, MapperA> transformerA;
#Inject
private TransformerImpl<ClazzBI, ClazzBO, MapperB> transformerB;
The problem :
But Spring is not able to instantiate those 2 objects because it founds 2 implementations of Mapper : MapperA and MapperB even if I specify which implementation I want as a generic parameter.
Any idea how to make it without the need of instantiate all of those beans in a #Configuration class ?
You're asking for a singleton but requiring two injection points
#Inject
private TransformerImpl<ClazzAI, ClazzAO, MapperA> transformerA;
#Inject
private TransformerImpl<ClazzBI, ClazzBO, MapperB> transformerB;
for differently constructed objects. That doesn't make much sense.
You now realize you need two beans. If you can't (don't want to) do it in a #Configuration class with #Bean factory methods, you'll need to declare (and scan) two separate #Component classes. (I made your parent constructor public here.)
#Component
class MapperATransformerImpl extends TransformerImpl<ClazzAI, ClazzAO, MapperA> {
#Inject
public MapperATransformerImpl(MapperA mapper) {
super(mapper);
}
}
#Component
class MapperBTransformerImpl extends TransformerImpl<ClazzBI, ClazzBO, MapperB> {
#Inject
public MapperBTransformerImpl(MapperB mapper) {
super(mapper);
}
}
When processing the injection target
#Inject
private TransformerImpl<ClazzAI, ClazzAO, MapperA> transformerA;
Spring will find the MapperATransformerImpl, which is of type TransformerImpl<ClazzAI, ClazzAO, MapperA> and inject that.
Try with Spring 4. See Using generics as autowiring qualifiers
Edit
Like #SotiriosDelimanolis explained in his answer, Spring 4 can use type parameter information as qualifiers to select which bean definition matches a particular injection point, but in the end, it will only match against bean definition with concrete type definitions. In your case, the problem is that you need a TransformerImpl bean definition for each concrete type you want to inject.
As an alternative to defining all bean definition explicitly, check my answer to Spring autowiring issues on paramaterized class
Let's assume I have this code:
#Controller
#RequestMapping("/something")
public class SomeController {
#Autowired
private SomeService aService;
#RequestMapping("/doStuff")
public void doStuff(#RequestParam("type") String type) {
aService.doStuff();
}
}
In my application I need to call a specific service depending on the specified type. All services implements the same interface. If I understand correctly SomeService cannot be an interface. I could use a service factory and instantiate the service depending on the type every time a new request is done, but this doesn't look very efficient.
Alternatively I could use a different controller for each different type of service (and encode the type in the REST URI), but this would imply a lot of code duplication since all the services basically implements the same interface.
My question is, assuming the called service depends on the passed parameter, what is the best pattern to adopt for this scenario?
Similar to RC.'s answer, instead of using a Map and adding the values by you, just let the Spring BeanFactory handle this for you:
#Controller
#RequestMapping("/something")
public class SomeController {
#Autowired
private BeanFactory beanFactory;
#RequestMapping("/doStuff")
public void login(#RequestParam("type") String type) {
SomeService aService = (SomeService)beanFactory.getBean(type);
aService.doStuff();
}
}
You could use a map here, something along this:
#Controller
#RequestMapping("/something")
public class SomeController {
#Autowired
private SomeService someService;
#Autowired
private SomeOtherService someOtherService;
// ...
private final Map<String, ServiceCommonInterface> serviceMap = new HashMap<>();
#PostConstruct
private void postConstruct() {
serviceMap.put(typeForSomeService, someService);
serviceMap.put(typeForSomeOtherService, someOtherService);
}
#RequestMapping("/doStuff")
public void login(#RequestParam("type") String type) {
// TODO: ensure type is correct (an enum might be handy here)
serviceMap.get(type).doStuff();
}
}
Or better, as stated in comments you can leverage qualifiers:
#Controller
#RequestMapping("/something")
public class SomeController {
#Autowired
private ApplicationContext applicationContext;
#RequestMapping("/doStuff")
public void login(#RequestParam("type") String type) {
// TODO: ensure type is a correct bean name
applicationContext.getBean(type, ServiceCommonInterface.class).doStuff();
}
}
Depending on the number of types you wish to support there are two options I see.
1) Autowire in a factory as you mentioned and lazily create each service as needed. If the services are stateless you could keep a reference to the object after created so would only need to create once per type.
2) Autowire in a Spring Map with the key being your types and the value being the correct service to use. Then when your receive the type, can retrieve the correct service impl for your map.
For example for map: http://www.mkyong.com/spring/spring-collections-list-set-map-and-properties-example/ or see How to inject a Map<String, List> in java springs?
Both of these require you to create an interface for your service which is something you said is possible.
I have a service bean capable of getting / setting property values from persistent layer (eg: database). Something like this:
#Service
public ConfigService {
public String getConfig(String key);
}
The problem is for each controller class I write I have to autowire and populate my model with the property key/values:
#Controller
#RequestMapping("/foo")
public FooController {
#Autowired private ConfigService configService;
#RequestMapping("/login")
public String login(Model model) {
model.addAttribute("site.name", configService.getConfig("site.name"));
//...
}
}
Is there any way I can automatically get the value of this property on my spring JSP view? I don't want to have to inject this to my model object for each controller class I write.
The closest I can get so far is using Spring ResourceBundleMessageSource bean and <spring:message> tags, however I am constrained to using properties file, can't store it in database.
I found another way of doing this. Use a #ControllerAdvice class combined with #ModelAttribute method. Something like this:
#ControllerAdvice
public class ConfigAdvice {
#Autowired private ConfigService configService;
#ModelAttribute
public void populateConfig(Model model) {
for(Config config : configService.getAll()) {
model.addAttribute(config.getKey(), config.getValue());
}
}
}
The #ModelAttribute annotated populateConfig() method above will run prior to any #RequestMapping method on all other controller classes.
One drawback is config key can't contain any dot characters.
So far this looks to be my best option. Please let me know if there's a better way.