I am creating two constructor for my jersey resource, however only one is the one being able to call,
here is the sample code,
public class jerseyresoure {
private String name;
private int age;
#Inject
public jerseyresoure (String name){
this.name = name;
}
#Inject
public jerseyresoure (int age){
this.age= age;
}
}
the get cosntructor with the parameter int is the one being called successfully,
can you help me with this scenario?
According to the CDI specification it is illegal to annotate more than one constructor with #Inject (see section 3.9 of the CDI specification):
If a bean class does not explicitly declare a constructor using #Inject, the constructor that accepts no parameters is the bean
constructor.
If a bean class has more than one constructor annotated #Inject, the container automatically detects the problem and treats it
as a definition error.
A bean constructor may have any number of parameters. All parameters of a bean constructor are injection points.
So what you can do is as follows:
public class jerseyresoure {
private String name;
private int age;
#Inject
public jerseyresoure (String name, int age){
this.name = name;
this.age = age;
}
}
I assume you are using a producer method so that values (name and age) get injected.
Related
assume there is a class Person
class Person{
private Address add;
}
class Address{
String street;
}
The moment I create a bean of Person class then I need a person bean to have address property with value street as "baker lane". Is it possible to use autowire in Person class to achieve this or it cannot be achieved at all?
This was an interview question by the way
we can set default value in Spring expression
#{expression?:default value}
//set deafult value for street
#Value("#{address.street ?: 'baker lane'}")
private String street;
You can use Autowiring on your constructor and modify the behavior of person.
Your interviewer probably expected the following to be explained
#Component
class Person{
private Address add;
#Autowired
public Person(Address add) { <--- An instance of Address will be injected here
this.add = add;
//this.add.setStreet("Custom Street"); <--- you can modify that here before the Autowiring constructor ends
/* if (add.getStreet().isEmpty()) { <--- you can do whatever you want inside the constructor
add.setStreet("Should not be empty") <--- you can check conditionally and set everything you want
} */
}
}
#Component
class Address{
String street;
}
I have a class that contain injections and mandatory(final) fields. For common I can use MicronautBeanFactory.getBean(type) OR BeanContext.getBean(type) to get bean from context, but in this situation I must pass type and args.
I've created simple test for this
#MicronautTest
public class ETLExecutorTest {
#Inject
private MicronautBeanFactory micronautBeanFactory;
#Test
void testGetBean() {
Object[] args = new Object[] {"name", "spec", 1L};
ObjectInstance instance = micronautBeanFactory.getBean(ObjectInstance.class, args);
}
}
Object(bean) code
#Prototype
public class ObjectInstance {
#Inject
private ObjectStorage objectStorage;
private final String name;
private final String spec;
private final Long id;
public ObjectInstance(String name, String spec, Long id) {
this.name = name;
this.spec = spec;
this.id = id;
}
}
When I run it I receive exception
io.micronaut.context.exceptions.DependencyInjectionException: Failed to inject value for parameter [name] of class: com.ObjectInstance
Message: Multiple possible bean candidates found: [java.lang.String, java.lang.String, java.lang.String]
Path Taken: new ObjectInstance([String name],String specName,Long accountId)
at io.micronaut.context.AbstractBeanDefinition.getBeanForConstructorArgument(AbstractBeanDefinition.java:1016)
at com.$TableInstanceDefinition.build(Unknown Source)
at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1598)
at io.micronaut.context.DefaultBeanContext.getScopedBeanForDefinition(DefaultBeanContext.java:2076)
at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:1991)
at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:1963)
at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:610)
at io.micronaut.spring.context.factory.MicronautBeanFactory.getBean(MicronautBeanFactory.java:264)
Caused by: io.micronaut.context.exceptions.NonUniqueBeanException: Multiple possible bean candidates found: [java.lang.String, java.lang.String, java.lang.String]
at io.micronaut.context.DefaultBeanContext.findConcreteCandidate(DefaultBeanContext.java:1701)
at io.micronaut.context.DefaultApplicationContext.findConcreteCandidate(DefaultApplicationContext.java:395)
at io.micronaut.context.DefaultBeanContext.lastChanceResolve(DefaultBeanContext.java:2289)
at io.micronaut.context.DefaultBeanContext.findConcreteCandidateNoCache(DefaultBeanContext.java:2212)
at io.micronaut.context.DefaultBeanContext.lambda$findConcreteCandidate$57(DefaultBeanContext.java:2155)
at io.micronaut.core.util.clhm.ConcurrentLinkedHashMap.lambda$compute$0(ConcurrentLinkedHashMap.java:721)
at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660)
at io.micronaut.core.util.clhm.ConcurrentLinkedHashMap.compute(ConcurrentLinkedHashMap.java:733)
at io.micronaut.core.util.clhm.ConcurrentLinkedHashMap.computeIfAbsent(ConcurrentLinkedHashMap.java:710)
at io.micronaut.context.DefaultBeanContext.findConcreteCandidate(DefaultBeanContext.java:2154)
at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:1943)
at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:1082)
at io.micronaut.context.AbstractBeanDefinition.getBeanForConstructorArgument(AbstractBeanDefinition.java:1007)
Also I tried to do another test, but in this case I receive object without injected fields
#MicronautTest
public class ETLExecutorTest {
#Inject
private BeanContext beanContext;
#Test
void testGetBean() {
Object[] args = new Object[] {"name", "spec", 1L};
BeanDefinition<ObjectInstance> definition = beanContext.getBeanDefinition(ObjectInstance.class);
ObjectInstance instance = definition.getConstructor().invoke(args); // there are no injections here: ObjectStorage of instance = null.
}
}
Could you tell me, please, what I do wrong ???
micronaut trying to create bean ObjectInstance through the constructor but can't find String name to inject, looks like it’s just a simple field for the ObjectInstance and in this case, it works as expected:
io.micronaut.context.exceptions.DependencyInjectionException: Failed to inject value for parameter [name]
if you add a default constructor, then the ObjectInstance will be created and you can get bean via beanContext.getBean(ObjectInstance.class):
#Prototype
public class ObjectInstance {
#Inject
private ObjectStorage objectStorage;
private String name;
private String spec;
private Long id;
public ObjectInstance() {}
public ObjectInstance(String name, String spec, Long id) {
this.name = name;
this.spec = spec;
this.id = id;
}
}
Also pay attention to MicronautBeanFactory implements ListableBeanFactory, this is for integration with Spring
P.S. I would recommend you change your code structure, POJO should not contain beans
This question already has answers here:
Dependency injection with autowire="constructor" when multiple constructors are present?
(2 answers)
Closed 6 years ago.
I have three beans: Movie, Director, Hero
Movie bean:
public class Movie {
private Director director;
private String name;
private Hero hero;
public Movie(Director director, Hero hero) {
System.out.println("m1");
this.director = director;
this.name = name;
this.hero = hero;
}
public Movie(Director director, String name) {
System.out.println("m2");
this.director = director;
this.name = name;
}
public Movie(Director director) {
System.out.println("m3");
this.director = director;
}
public Movie() {
System.out.println("m4");
}
}
Director and Hero beans:
public class Director {
}
public class Hero {
}
spring-core.xml
<bean id="movieBean" class="Movie" autowire="constructor" />
<bean id="directorBean" class="Director"></bean>
<bean id="heroBean" class="Hero"></bean>
Please note in the above XML I have declared all the three beans
MainClass
ApplicationContext context = new ClassPathXmlApplicationContext("spring-core.xml");
Movie movie = (Movie) context.getBean("movieBean");
System.out.println(movie);
The output is "m1" i.e. the constructor called is Movie(Director director, Hero hero)
My question is: why only this constructor is called and how IOC container will choose among multiple constructor while injecting dependencies if we are using autowiring using constructor
Only one constructor can be called to instantiate the bean. This is similar to how when creating a new Object you only invoke one constructor (If you want to be really precise, yes you could chain constructors calling this)
In this case the constructor with most arguments that can be satisfied by other beans available in the context will be used.
I'm playing with java standard CDI and there is one concept I cannot get my head around. In the example below the Application class "requires" the Person class which cannot be injected since it has non-zero args constructor. How should I handle this scenario with CDI?
#Default
class Person {
private String name;
Person(String name) {
this.name=name;
}
String getName() {
return this.name;
}
}
class Application {
#Inject
public Application(Instance<Person> p)
}
There are three ways to inject objects without a no-args constructor. One is to use a producer to create the object.
#Produces
private Person producePerson() {
return new Person(name);
}
The second is to annotate one of the constructors with #Inject and make sure all of the parameters are valid injection targets.
class Person {
private String name;
#Inject
Person(String name) {
this.name=name;
}
String getName() {
return this.name;
}
}
and somewhere else:
#Produces
private String producePersonName() {
return name;
}
(Setting up multiple of these kinds of injections may require creating some qualifier annotations)
The third is to mess around with CDI container initialization with a custom extension, but that is overkill for such a relatively simple need.
I was wondering it there is any good way without creating separate bean and breaking DRY principle if I want to expose different values.
For example here is the "GET" bean :
class NameBean {
#XMLAttribute
String name;
int age;
String ssn;
}
But when I "POST" I wont need ssn. Do I really have to create another bean if I don't want "ssn" in the json.
class PostNameBean {
#XMLAttribute
String name;
int age;
}
You can pass nillable = true on your ssn field and clearly document that the field is not required when the user posts the data.
http://www.w3schools.com/schema/el_element.asp