Friday, 21 September 2018

Apply @Resource Annotation in constructor in Spring Autowiring | Spring - @Resource annotation

Enjoying Spring Framework Tutorials?

Subscribe to Ram N Java for easy, practical Java and Spring tutorials!

Subscribe on YouTube

Can You Use @Resource with Constructor Injection?

In Spring Framework, dependency injection can be performed using fields, setter methods, or constructors. A frequent question among developers is: Can we apply the @Resource annotation directly to a constructor?

The short answer is no. If you try to use @Resource directly on a constructor, you will encounter a compilation error. Let us dive into why this happens and what alternatives you should use instead.

The Compilation Error Explained

Suppose you create an Employee class and try to inject dependencies through its constructor using @Resource:

public class Employee {
    private String name;
    private Address address;

    // Disallowed! Causes compile-time error
    @Resource
    public Employee(Address address) {
        this.address = address;
    }
}

The Java compiler will fail with an error stating:

"The annotation @Resource is disallowed for this location."

Why Does This Happen?

The @Resource annotation belongs to the Java standard library (javax.annotation.Resource / jakarta.annotation.Resource). If you examine the annotation definition, its target types are restricted to:

  • TYPE: Classes and interfaces
  • FIELD: Class properties/fields
  • METHOD: Setter and regular methods

Notice that CONSTRUCTOR is completely missing from its @Target list. Because of this definition, Java does not permit the annotation on constructors.

Recommended Solutions

If you need constructor injection in Spring, use @Autowired instead:

@Autowired
public Employee(Address address) {
    this.address = address;
}

If you specifically want to use @Resource, place it over the field or over the setter method rather than the constructor.

Related Spring Tutorials to Watch Next


Click here to watch on Youtube:
https://www.youtube.com/watch?v=5qNR7AZmfIo&list=UUhwKlOVR041tngjerWxVccw

Click the below Image to Enlarge:
Apply @Resource Annotation in constructor in Spring Autowiring | Spring - @Resource annotation

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0%20http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.ram.core</groupId>
    <artifactId>SpringDemo</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>SpringDemo</name>
    <url>http://maven.apache.org</url>

    <properties>
        <spring.version>5.0.2.RELEASE</spring.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>

        <!-- Spring 5 dependencies -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
    </dependencies>
</project>

Address.java

package com.ram.model;

public class Address
{
    private String city;
    private String state;
    private String country;

    public Address(String city, String state, String country)
    {
        this.city = city;
        this.state = state;
        this.country = country;
    }

    @Override
    public String toString()
    {
        return "Address [city=" + city + ", state=" + state + ", country="
                + country + "]";
    }

}

Employee.java

package com.ram.model;

import javax.annotation.Resource;

public class Employee
{
    private String name;
    private Address address;

    @Resource
    public Employee(String name, Address address)
    {
        System.out.println("Employee(String name, Address address) constructor "
                + "is called by the Spring container");
        this.name = name;
        this.address = address;
    }

    public void displayEmployeeDetails()
    {
        System.out.println(
                "Employee [name=" + name + ", address=" + address + "]");
    }

}

applicationContext.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-4.3.xsd">


    <context:annotation-config />

    <bean id="address" class="com.ram.model.Address">
        <constructor-arg value="Chennai"></constructor-arg>
        <constructor-arg value="Tamil Nadu"></constructor-arg>
        <constructor-arg value="India"></constructor-arg>
    </bean>

    <bean id="employee" class="com.ram.model.Employee">
        <constructor-arg value="Peter"></constructor-arg>
    </bean>

</beans>


App.java

package com.ram.core;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.ram.model.Employee;

public class App
{
    public static void main(String[] args)
    {
        ApplicationContext context = new ClassPathXmlApplicationContext(
                "applicationContext.xml");

        System.out.println("---------------------------------------");

        Employee employee = (Employee) context.getBean("employee");
        System.out.println(
                "Got employee object from the ApplicationContext[Spring Container]");
     
        employee.displayEmployeeDetails();
    }

}

Output

Aug 23, 2018 9:23:02 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@5a2e4553: startup date [Thu Aug 23 09:23:02 IST 2018]; root of context hierarchy
Aug 23, 2018 9:23:02 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [applicationContext.xml]
Aug 23, 2018 9:23:03 AM org.springframework.context.support.AbstractApplicationContext refresh
WARNING: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'employee' defined in class path resource [applicationContext.xml]: Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.ram.model.Employee]: Constructor threw exception; nested exception is java.lang.Error: Unresolved compilation problem:
    The annotation @Resource is disallowed for this location

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'employee' defined in class path resource [applicationContext.xml]: Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.ram.model.Employee]: Constructor threw exception; nested exception is java.lang.Error: Unresolved compilation problem:
    The annotation @Resource is disallowed for this location

    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:278)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1270)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1127)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:545)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:502)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:312)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:310)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:758)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:868)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:144)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:85)
    at com.ram.core.App.main(App.java:12)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.ram.model.Employee]: Constructor threw exception; nested exception is java.lang.Error: Unresolved compilation problem:
    The annotation @Resource is disallowed for this location

    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:175)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:117)
    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:271)
    ... 14 more
Caused by: java.lang.Error: Unresolved compilation problem:
    The annotation @Resource is disallowed for this location

    at com.ram.model.Employee.<init>(Employee.java:10)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
    at java.lang.reflect.Constructor.newInstance(Unknown Source)
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:163)
    ... 16 more

Click the below link to download the code:
https://sites.google.com/site/ramj2eev2/java_basics/SpringDemo_Resource_annotation_cons.zip?attredirects=0&d=1

Github Link:
https://github.com/ramram43210/javaee/tree/master/Spring_2018/SpringDemo_Resource_annotation_cons

Bitbucket Link:
https://bitbucket.org/ramram43210/spring/src/02e04aa1b68a77d4f5a01ebf111e80370bd99ca8/Spring_2018/SpringDemo_Resource_annotation_cons/?at=master

See also:

  • All JavaEE Videos Playlist
  • All JavaEE Videos
  • All JAVA EE Links
  • Spring Tutorial
  • Servlets Tutorial
  • All Design Patterns Links
  • JDBC Tutorial
  • Java Collection Framework Tutorial
  • JAVA Tutorial
  • Kids Tutorial
  • Cooking Tutorial
  • No comments:

    Post a Comment

    Tutorials