Open In App

Java Spring – Using @PropertySource Annotation and Resource Interface

Last Updated : 21 Feb, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

In Java applications, Sometimes we might need to use data from external resources such as text files, XML files, properties files, image files, etc., from different locations (e.g., a file system, classpath, or URL). 

@PropertySource Annotation

To achieve this, the Spring framework provides the @PropertySource annotation as a facility to read and load the contents of a .properties file (i.e., key-value pairs) to set up bean properties in our application. 

@Target(value=TYPE)
@Retention(value=RUNTIME)
@Documented
@Repeatable(value=PropertySources.class)
public @interface PropertySource

We need to use this annotation along with PropertySourcesPlaceholderConfigurer class. This class resolves the placeholders within bean definition property values.

Resource Interface

In addition to this, Spring also has a resource loader mechanism that provides a unified Resource interface. Using this interface we can retrieve any type of external resource by a resource path. 

public interface Resource
extends InputStreamSource

All we need to do is to specify different prefixes for this path to load resources from different locations with the @Value annotation. 

How it works

To demonstrate this concept, let’s take a simple example of a Shopping application in which we will be having different categories of products and their details listed. First, we create the ShoppingCategory.java class as follows:

Java




package com.geeksforgeeks.shop;
 
import java.util.ArrayList;
import java.util.List;
 
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
 
@Component
@Scope("prototype")
public class ShoppingCategory {
     
    private List<Product> items = new ArrayList<>();
 
    public void addItem(Product item) {
        items.add(item);
    }
 
    public List<Product> getItems() {
        return items;
    }
 
}


Here, we are creating separate lists for each category of products. Now, we will create Product.java bean class to specify product variables and getter/setter methods.

Java




package com.geeksforgeeks.shop;
 
public class Product {
     
    private String name;
    private double price;
    private int discount;
 
    public Product() {
    }
 
    public Product(String name, double price, int discount) {
        this.name = name;
        this.price = price;
        this.discount = discount;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public double getPrice() {
        return price;
    }
 
    public void setPrice(double price) {
        this.price = price;
    }
     
    public int getDiscount() {
        return discount;
    }
 
    public void setDiscount(int discount) {
        this.discount = discount;
    }
 
    public String toString() {
        return name + " " + price + " - " + discount + "% discount!";
    }
 
}


Assume we have a series of values in a properties file we want to access to set up bean properties. Typically, a properties file can be the configuration properties of a database or some other application values composed of key values. In this example, we take the following discount rates (as key values) stored in a file called discounts.properties.

specialcustomer.discount=12
summer.discount=8
product.discount=5

Now, we will create ShoppingCategoryConfig.java class as follows.

Java




package com.geeksforgeeks.shop.config;
 
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
 
import com.geeksforgeeks.shop.Product;
 
@Configuration
@PropertySource("classpath:discounts.properties")
@ComponentScan("com.geeksforgeeks.shop")
public class ShoppingCategoryConfig {
     
    @Value("${specialcustomer.discount:0}")
    private int specialCustomerDiscount;
 
    @Value("${summer.discount:0}")
    private int specialSummerDiscount;
 
    @Value("${product.discount:0}")
    private int productDiscount;
 
    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }
     
    @Bean
    public Product asus() {
        Product d1 = new Product("ASUS", 65000, specialSummerDiscount);
        return d1;
    }
     
    @Bean
    public Product redmi() {
        Product d1 = new Product("REDMI", 57000, productDiscount);
        return d1;
    }
     
    @Bean
    public Product hp() {
        Product d1 = new Product("HP", 70000, specialSummerDiscount);
        return d1;
    }
     
    @Bean
    public Product oneplus() {
        Product d1 = new Product("ONEPLUS", 55000, specialSummerDiscount);
        return d1;
    }
     
    @Bean
    public Product samsung() {
        Product d1 = new Product("SAMSUNG", 62000, specialCustomerDiscount);
        return d1;
    }
 
}


Here, we are using @PropertySource annotation with a value of classpath:discounts.properties in the Java config class. The classpath: prefix tells the Spring to search for the discounts.properties file in the Java classpath. Once we define the @PropertySource annotation to load the properties file, as we discussed earlier, we also need to define a PropertySourcePlaceholderConfigurer bean with the @Bean annotation. Then, Spring automatically wires the @PropertySource – discounts.properties file. Now the properties in the file become accessible as bean properties. Next, we need to define Java variables to take values from the properties file. To do this, we need to use the @Value annotation with a placeholder expression. The syntax is:

@Value("${key:default_value}")

Then, a search is done for the key value in all the loaded application properties. If a matching key=value is found in the properties file, then the corresponding value is assigned to the bean property. If no matching value is found, default_value (i.e., after ${key:) is assigned to the bean property. To test this we need to create Main.java class as follows:

Java




package com.geeksforgeeks.shop;
 
import java.util.Properties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.geeksforgeeks.shop.config.ShoppingCategoryConfig;
 
public class Main {
     
    public static void main(String[] args) throws Exception{
         
        ApplicationContext context = new AnnotationConfigApplicationContext(ShoppingCategoryConfig.class);
         
        Product asus = context.getBean("asus", Product.class);
        Product redmi = context.getBean("redmi", Product.class);
        Product hp = context.getBean("hp", Product.class);
        Product oneplus = context.getBean("oneplus", Product.class);
        Product samsung = context.getBean("samsung", Product.class);
         
        ShoppingCategory laptops = context.getBean("shoppingCategory", ShoppingCategory.class);
        laptops.addItem(asus);
        laptops.addItem(redmi);
        laptops.addItem(hp);
        System.out.println("Category : Laptops");
        System.out.println(laptops.getItems());
        System.out.println();
         
        ShoppingCategory mobiles = context.getBean("shoppingCategory", ShoppingCategory.class);
        mobiles.addItem(oneplus);
        mobiles.addItem(samsung);
        System.out.println("Category : Mobile phones");
        System.out.println(mobiles.getItems());
        System.out.println();               
    }
 
}


If we run the project, the output will be as follows.

Output:

Output

Output – @PropertySource annotation

Here we can see the discount values as the java variables are set up as the bean instances for a bean’s discount property. This is for reading the .properties file to set up bean instances. But, If we want to use properties file or any other file data for a different purpose than setting up bean properties, we should use Spring’s Resource mechanism. Let’s consider the same example, and we need to add some text that involves some offer details at the end of the shopping page. So, consider we have a text file with some data like below. 

offer.txt

*** Special offer only for today - Get flat 25% discount on purchase of total 1 lakh ***

To read this data into our application, we need to use the Resource interface as below in Main.java class.

Java




package com.geeksforgeeks.shop;
 
import java.util.Properties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import com.geeksforgeeks.shop.config.ShoppingCategoryConfig;
 
public class Main {
     
    public static void main(String[] args) throws Exception{
         
        ApplicationContext context = new AnnotationConfigApplicationContext(ShoppingCategoryConfig.class);
         
        Product asus = context.getBean("asus", Product.class);
        Product redmi = context.getBean("redmi", Product.class);
        Product hp = context.getBean("hp", Product.class);
        Product oneplus = context.getBean("oneplus", Product.class);
        Product samsung = context.getBean("samsung", Product.class);
         
        ShoppingCategory laptops = context.getBean("shoppingCategory", ShoppingCategory.class);
        laptops.addItem(asus);
        laptops.addItem(redmi);
        laptops.addItem(hp);
        System.out.println("Category : Laptops");
        System.out.println(laptops.getItems());
        System.out.println();
         
        ShoppingCategory mobiles = context.getBean("shoppingCategory", ShoppingCategory.class);
        mobiles.addItem(oneplus);
        mobiles.addItem(samsung);
        System.out.println("Category : Mobile phones");
        System.out.println(mobiles.getItems());
        System.out.println();
         
        Resource resource = new ClassPathResource("offer.txt");
        Properties props = PropertiesLoaderUtils.loadProperties(resource);
        System.out.println(props);       
    }
 
}


Here, we are using the ClassPathResource, which tells the spring to look for the offer.txt file in the java classpath. And using the PropertiesLoaderUtils, it reads and loads all the content in the file. If the external resource file is not in the classpath but in some file system path, then we need to use FileSystemResource.

Resource resource = new FileSystemResource("d:/shop/offer.txt")

If the external resource file is at a URL, the resource would be loaded with UrlResource.

Resource resource = new UrlResource("http://www.geeksforgeeks.com/")

Now the output will be as follows.

Output:

Output

Output – Resource interface

The final project structure will be as follows:

project structure

Project Structure

This way, we can use the @PropertySource annotation and Resource interface to use the data from External Resources such as Text Files, XML Files, Properties Files, Image Files, etc. in our application.



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads