Spring @Required
annotation marks a method as being required.
If the setter method is not configured with a value, then spring container will throw BeanCreationException
during the initialization phase of the bean.
The required properties check happens before the container starts applying the property values on to the bean.
In this article, we will see several examples of @Required
annotation including how to use a custom annotation and how to skip a required annotation check if we ever want to?
This example uses the following frameworks:
Dependencies
Add the following dependencies:
spring-core
spring-context
spring-beans
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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.javarticles.spring</groupId> <artifactId>springListExample</artifactId> <version>0.0.1-SNAPSHOT</version> <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> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> </dependencies> <properties> <spring.version>4.1.6.RELEASE</spring.version> </properties> </project>
Required Annotation Example
Annotate the setter method with @Required
annotation in order to make sure that the JavaBean property has been been configured.
In the below example, name property of Company
class is annotated with @[email protected]
annotation only makes sure that a property is configured with a value and doesn’t care whether the value is not null.
Company:
package com.javarticles.spring; import org.springframework.beans.factory.annotation.Required; public class Company { private String name; public String getName() { return name; } @Required public void setName(String name) { this.name = name; } public String toString() { return "Company(" + name + ")"; } public static Company create() { return new Company(); } }
Likewise, Employee
bean’s setName()
and setCompany()
are annotated with @Required
as we do want to know employee’s name and the company an employee belongs to.
Employee:
package com.javarticles.spring; import org.springframework.beans.factory.annotation.Required; public class Employee { private String name; private Company company; private int age; public String getName() { return name; } @Required public void setName(String name) { this.name = name; } public Company getCompany() { return company; } @Required public void setCompany(Company company) { this.company = company; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String toString() { return "Employee(" + name + "), " + company; } }
RequiredAnnotationBeanPostProcessor
is a Spring bean post processor that checks if all the bean properties with the @Required annotation
have been configured. To enable this bean post processor for property checking, you must register it in the Spring IoC container. We can register the bean either using <context:annotation-config/>
or <context:component-scan/>
tags.
requiredPropertyMissingContext.xml:
<?xml version="1.0" encoding="UTF-8"?> <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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:annotation-config/> <bean id="dreamCompany" class="com.javarticles.spring.Company"> <property name="name" value="Dream Company"></property> </bean> <bean id="sam" class="com.javarticles.spring.Employee"/> </beans>
When we try to load the above context XML, context fails with BeanCreationException
as the required properties name
and company
are missing in the configuration of Employee
bean.
SpringRequiredAnnotationExample:
package com.javarticles.spring; import org.springframework.beans.factory.BeanCreationException; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringRequiredAnnotationExample { public static void main(String[] args) { try { System.out.println("Loading context file with missing required properties..."); new ClassPathXmlApplicationContext("requiredPropertyMissingContext.xml"); } catch (BeanCreationException e) { System.out.println("Bean creation failed, exception " + e.getRootCause()); } } }
The error message contains the property names of the setter methods which are annotated with @Required
but are not configured.
Output:
Loading context file with missing required properties... Bean creation failed, exception org.springframework.beans.factory.BeanInitializationException: Properties 'company' and 'name' are required for bean 'sam'
Let’s configure the missing properties…
withRequiredPropertiesContext.xml:
<?xml version="1.0" encoding="UTF-8"?> <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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:annotation-config/> <bean id="dreamCompany" class="com.javarticles.spring.Company"> <property name="name" value="Dream Company"></property> </bean> <bean id="sam" class="com.javarticles.spring.Employee"> <property name="name" value="Sam"/> <property name="company" ref="dreamCompany"/> </bean> </beans>
SpringRequiredAnnotationExample:
package com.javarticles.spring; import org.springframework.beans.factory.BeanCreationException; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringRequiredAnnotationExample { public static void main(String[] args) { try { System.out.println("Loading context file with missing required properties..."); new ClassPathXmlApplicationContext("requiredPropertyMissingContext.xml"); } catch (BeanCreationException e) { System.out.println("Bean creation failed, exception " + e.getRootCause()); } ClassPathXmlApplicationContext context = null; try { System.out.println("Loading context file with all required properties..."); context = new ClassPathXmlApplicationContext("withRequiredPropertiesContext.xml"); System.out.println(context.getBean("sam")); } finally { if (context != null) { context.close(); } } } }
Output:
Loading context file with missing required properties... Bean creation failed, exception org.springframework.beans.factory.BeanInitializationException: Properties 'company' and 'name' are required for bean 'sam' Loading context file with all required properties... Employee(Sam), Company(Dream Company)
Custom Required Annotation Example
If you want to provide your own annotation type, you can do it by defining one and then manually configuring RequiredAnnotationBeanPostProcessor
bean, with property requiredAnnotationType
set to the custom defined annotation type.
Define a custom annotation.
CompanyRequired:
package com.javarticles.spring; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface CompanyRequired { }
Annotate the setter method with the above custom type.
Entrepreneur:
package com.javarticles.spring; public class Entrepreneur { private String company; public String getCompany() { return company; } @CompanyRequired public void setCompany(String company) { this.company = company; } }
Register RequiredAnnotationBeanPostProcessor
bean
customRequiredAnnotationContext.xml:
<?xml version="1.0" encoding="UTF-8"?> <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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <bean id="" class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"> <property name="requiredAnnotationType" value="com.javarticles.spring.CompanyRequired"/> </bean> <bean id="entrepreneur" class="com.javarticles.spring.Entrepreneur"/> </beans>
SpringRequiredAnnotationExample:
package com.javarticles.spring; import org.springframework.beans.factory.BeanCreationException; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringRequiredAnnotationExample { public static void main(String[] args) { try { System.out.println("Loading context file with missing required properties..."); new ClassPathXmlApplicationContext("requiredPropertyMissingContext.xml"); } catch (BeanCreationException e) { System.out.println("Bean creation failed, exception " + e.getRootCause()); } ClassPathXmlApplicationContext context = null; try { System.out.println("Loading context file with all required properties..."); context = new ClassPathXmlApplicationContext("withRequiredPropertiesContext.xml"); System.out.println(context.getBean("sam")); } finally { if (context != null) { context.close(); } } try { System.out.println("Loading context file with custom required annotation..."); context = new ClassPathXmlApplicationContext("customRequiredAnnotationContext.xml"); } catch (BeanCreationException e) { System.out.println("Bean creation failed, exception " + e.getRootCause()); } } }
Output:
Loading context file with missing required properties... Bean creation failed, exception org.springframework.beans.factory.BeanInitializationException: Properties 'company' and 'name' are required for bean 'sam' Loading context file with all required properties... Employee(Sam), Company(Dream Company) Loading context file with custom required annotation... Bean creation failed, exception org.springframework.beans.factory.BeanInitializationException: Property 'company' is required for bean 'entrepreneur'
Required Property Check where bean is created using Static Factory Method
You can create the bean using a factory method. If any of the bean’s setter methods are annotated with @Required
attribute the configuration check will still happen.
CompanyFactory:
package com.javarticles.spring; public class CompanyFactory { public static Company create() { return new Company(); } }
requiredPropertyMissingFactoryMethodContext.xml:
<?xml version="1.0" encoding="UTF-8"?> <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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:annotation-config/> <bean id="dreamCompany" class="com.javarticles.spring.CompanyFactory" factory-method="create"/> </beans>
SpringRequiredAnnotationFactoryMethodExample:
package com.javarticles.spring; import org.springframework.beans.factory.BeanCreationException; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringRequiredAnnotationFactoryMethodExample { public static void main(String[] args) { try { System.out.println("Loading context file with missing required properties, bean creation is through factory method ..."); new ClassPathXmlApplicationContext("requiredPropertyMissingFactoryMethodContext.xml"); } catch (BeanCreationException e) { System.out.println("Bean creation failed, exception " + e.getRootCause()); } } }
Output:
Loading context file with missing required properties, bean creation is through factory method ... Bean creation failed, exception org.springframework.beans.factory.BeanInitializationException: Property 'name' is required for bean 'dreamCompany'
Let’s add the missing properties.
withRequiredPropertiesFactoryMethodContext.xml:
<pre class="brush:xml"> <?xm> version="1.0" encoding="UTF-8"?> <beans xm>ns="http://www.springframework.org/schema/beans" xm>ns:xsi="http://www.w3.org/2001/XM>Schema-instance" xm>ns:context="http://www.springframework.org/schema/context" xsi:schema>ocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:annotation-config/> <bean id="dreamCompany" c>ass="com.javartic>es.spring.CompanyFactory" factory-method="create"> <property name="name" va>ue="Dream Company"/> </bean> </beans>
Output:
Loading context file with missing required properties, bean creation is through factory method ... Bean creation failed, exception org.springframework.beans.factory.BeanInitializationException: Property 'name' is required for bean 'dreamCompany' Loading context file with all required properties, bean creation is through factory method... Company(Dream Company)
Required Property Check where bean is created using Factory Bean
You can create the bean using a factory bean. If any of the bean’s setter methods are annotated with @Required
attribute the configuration check will still happen.
CompanyFactoryBean:
package com.javarticles.spring; import org.springframework.beans.factory.FactoryBean; public class CompanyFactoryBean implements FactoryBean { public static Company create() { return new Company(); } public Company getObject() throws Exception { return new Company(); } public Class<?> getObjectType() { return Company.class; } public boolean isSingleton() { return false; } }
requiredPropertyMissingFactoryBeanContext.xml:
<?xml version="1.0" encoding="UTF-8"?> <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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:annotation-config/> <bean id="companyFactory" class="com.javarticles.spring.CompanyFactoryBean"/> <bean id="dreamFactory" factory-bean="companyFactory"/> </beans>
SpringRequiredAnnotationFactoryBeanExample:
package com.javarticles.spring; import org.springframework.beans.factory.BeanCreationException; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringRequiredAnnotationFactoryBeanExample { public static void main(String[] args) { try { System.out.println("Loading context file with missing required properties, bean creation is through factory bean..."); new ClassPathXmlApplicationContext("requiredPropertyMissingFactoryBeanContext.xml"); } catch (BeanCreationException e) { System.out.println("Bean creation failed, exception " + e.getRootCause()); } } }
Output:
Loading context file with missing required properties, bean creation is through factory bean... Bean creation failed, exception java.lang.IllegalStateException: No bean class specified on bean definition
How to Skip @Required property check?
We you want the required property check to be skipped, you need to meta attribute element with key
as org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.skipRequiredCheck
and value
set to true
.
In the below example, we have configured a dummy employee bean with the ‘skipRequiredCheck’ attribute as the employee is just a dummy bean with no name or company.
skipRequiredPropertyCheckContext.xml:
<?xml version="1.0" encoding="UTF-8"?> <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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:annotation-config /> <bean id="dummy" class="com.javarticles.spring.Employee"> <meta key="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.skipRequiredCheck" value="true" /> </bean> </beans>
SpringSkipRequiredPropertCheckExample:
package com.javarticles.spring; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringSkipRequiredPropertCheckExample { public static void main(String[] args) { ClassPathXmlApplicationContext context = null; try { System.out.println("Loading context file with property marked as 'skip required property check'..."); context = new ClassPathXmlApplicationContext("skipRequiredPropertyCheckContext.xml"); System.out.println(context.getBean("dummy")); } finally { if (context != null) { context.close(); } } } }
Output:
Loading context file with property marked as 'skip required property check'... Employee(null), null
Download source code
This was an example about spring @Required annotation.