Google

Nov 30, 2011

Spring Interview Questions and Answers: read properties file

Spring Interview Questions and Answers Q1 - Q14 are FAQs

Q1 - Q4 Overview & DIP Q5 - Q8 DI & IoC Q9 - Q10 Bean Scopes Q11 Packages Q12 Principle OCP Q14 AOP and interceptors
Q15 - Q16 Hibernate & Transaction Manager Q17 - Q20 Hibernate & JNDI Q21 - Q22 read properties Q23 - Q24 JMS & JNDI Q25 JDBC Q26 Spring MVC Q27 - Spring MVC Resolvers

Q21. How do you read properties file in spring?
A21. PropertyPlaceholderConfigurer allows you to share a properties files. You can simply share one properties file for all of your build info or you can separate things out, and have multiple properties files in your build script.



Managing properties for an enterprise application can be a bit trickier than one might expect. The following link covers some basics around working with properties files.

Working with properties files


STEP 1: Prepare the properties file to use. The myapp.properties file contains name/value pairs as shwon below.

#statuses
order.status.rejected=REJECTED
order.status.filled=FILLED
order.status.shipped=SHIPPED

STEP 2: Define the interface and the implementation classes that read these properties.

package test;

public interface OrderNotification {
    abstract void processOrder();
}



The statuses are read from the above properties file.

package test;

import java.util.Map;

public class OrderNotificationImpl implements OrderNotification {

 //read from properties file
 private Map<string,string> statuses;

 public OrderNotificationImpl(Map<string,string> statuses) {
   this.statuses = statuses;
 }

 @Override
 public void processOrder() {
 //....
   System.out.println(statuses.get("REJECTED"));
 }
}

STEP 3: The beans3.xml that read properties file and inject relevant values.


<?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:tx="http://www.springframework.org/schema/tx"
 xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
 xmlns:jee="http://www.springframework.org/schema/jee"
 xsi:schemaLocation="
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
     http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd">


 <bean id="propertyPlaceholderConfigurer"
  class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  <property name="locations">
   <list>
    <value>classpath:test/myapp.properties</value>
   </list>
  </property>
 </bean>


 <!-- inject properties -->
 <bean id="orderStatus" class="java.util.LinkedHashMap">
  <constructor-arg>
   <map key-type="java.lang.String" value-type="java.lang.String">
    <entry key="REJECTED">
     <value>${order.status.rejected}</value>
    </entry>
    <entry key="FILLED">
     <value>${order.status.filled}</value>
    </entry>
    <entry key="SHIPPED">
     <value>${order.status.shipped}</value>
    </entry>
   </map>
  </constructor-arg>
 </bean>

 <!-- Use the order status map-->
 <bean id="orderNotification" class="test.OrderNotificationImpl">
  <constructor-arg>
   <ref bean="orderStatus" />
  </constructor-arg>
 </bean>

</beans>


STEP 4: Finally, the standalone client application that makes use of the OrderNotification.

package test;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestSpring3 {
    
    public static void main(String[] args) {
        ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
                new String[] {"test/beans3.xml"});
        BeanFactory factory = (BeanFactory) appContext;
        OrderNotification orderNotification = (OrderNotification)factory.getBean("orderNotification");
        orderNotification.processOrder();
       
    }   
}

If you run the above stand-alone application, you get the following output

30/11/2011 4:09:33 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@86c347: startup date [Wed Nov 30 16:09:33 EST 2011]; root of context hierarchy
30/11/2011 4:09:33 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [test/beans3.xml]
30/11/2011 4:09:34 PM org.springframework.core.io.support.PropertiesLoaderSupport loadProperties
INFO: Loading properties file from class path resource [test/myapp.properties]
30/11/2011 4:09:34 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@6c585a: defining beans [propertyPlaceholderConfigurer,orderStatus,orderNotification]; root of factory hierarchy
REJECTED


Q22. How would you go about reading environment specific property files?
A22. The properties file can be loaded via a file system.

STEP 1: Have the properties files in an external file system and not within the war or ear archives.

STEP 2: The beans3.xml will have the following change -- change classpath: to file:

<bean id="propertyPlaceholderConfigurer"
  class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  <property name="locations">
   <list>
    <value>file:${PROPERTIES_HOME}/test/myapp_${ENV}.properties</value>
   </list>
  </property>
</bean>


STEP 3: Provide the JVM arguments PROPERTIES_HOME and ENV.

java test.TestSpring3 -DPROPERTIES_HOME=C:\\opt2\\myapp   -DENV=dev 


STEP 4: The rest remain the same as previous example.


Q. How do you inject a java.util.Properties into your OrderNotification?
A.

STEP 1: Modify the OrderNotificationImpl as shown below. As you can se the, the java.utilProperties will be injected via setter injection.

package test;

import java.util.Map;
import java.util.Properties;

public class OrderNotificationImpl implements OrderNotification {
    
    private Map<string,string> statuses;
    private Properties appProperties;
    
    public OrderNotificationImpl(Map<string,string> statuses) {
       this.statuses = statuses;
    }

    @Override
    public void processOrder() {
        //....
        System.out.println(statuses.get("REJECTED"));
        System.out.println(appProperties.getProperty("order.status.shipped"));
    }

    public void setAppProperties(Properties appProperties) {
        this.appProperties = appProperties;
    }
}


STEP 2: Make some changes to the wiring. The beans4.xml uses the PropertiesFactoryBean and pass it to the PropertyPlaceholderConfigurer. Also, notice that the myappProperties is injected into orderNotification via setter injection.


<?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:tx="http://www.springframework.org/schema/tx"
 xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
 xmlns:jee="http://www.springframework.org/schema/jee"
 xsi:schemaLocation="
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
     http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd">


 <bean id="myappProperties"
  class="org.springframework.beans.factory.config.PropertiesFactoryBean">
  <property name="singleton" value="true" />

  <property name="ignoreResourceNotFound" value="true" />
  <property name="locations">
   <list>
    <value>classpath:test/myapp.properties</value>
   </list>
  </property>
 </bean>


    <bean id="propertyPlaceholderConfigurer"
  class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  <property name="properties" ref="myappProperties" /> 
 </bean>

 <!-- inject properties -->
 <bean id="orderStatus" class="java.util.LinkedHashMap">
  <constructor-arg>
   <map key-type="java.lang.String" value-type="java.lang.String">
    <entry key="REJECTED">
     <value>${order.status.rejected}</value>
    </entry>
    <entry key="FILLED">
     <value>${order.status.filled}</value>
    </entry>
    <entry key="SHIPPED">
     <value>${order.status.shipped}</value>
    </entry>
   </map>
  </constructor-arg>
 </bean>

 <!-- Use the order status map-->
 <bean id="orderNotification" class="test.OrderNotificationImpl">
  <constructor-arg>
   <ref bean="orderStatus" />
  </constructor-arg>
  <property name="appProperties" ref="myappProperties" />
 </bean>

</beans>



STEP 3: Finally, modify the TestSpring3 to use beans4.xml.

package test;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestSpring3 {
    
    public static void main(String[] args) {
        ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
                new String[] {"test/beans4.xml"});
        BeanFactory factory = (BeanFactory) appContext;
        OrderNotification orderNotification = (OrderNotification)factory.getBean("orderNotification");
        orderNotification.processOrder();     
    }   
}


STEP 3: Finally, modify the TestSpring3 to use beans4.xml.

package test;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestSpring3 {
    
    public static void main(String[] args) {
        ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
                new String[] {"test/beans4.xml"});
        BeanFactory factory = (BeanFactory) appContext;
        OrderNotification orderNotification = (OrderNotification)factory.getBean("orderNotification");
        orderNotification.processOrder();     
    }   
}

The output will be:

01/12/2011 11:15:55 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1f42b49: startup date [Thu Dec 01 11:15:55 EST 2011]; root of context hierarchy
01/12/2011 11:15:55 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [test/beans4.xml]
01/12/2011 11:15:56 AM org.springframework.core.io.support.PropertiesLoaderSupport loadProperties
INFO: Loading properties file from class path resource [test/myapp.properties]
01/12/2011 11:15:56 AM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@12a55aa: defining beans [myappProperties,propertyPlaceholderConfigurer,orderStatus,orderNotification]; root of factory hierarchy
REJECTED
SHIPPED




Q. How would you use annotations to inject properties?
A. Spring 3.0 makes use of annotations, and the properties can be injected




private @Value("${propertyName}") String propertyField;



More Spring Interview Questions and Answers

Labels:

0 Comments:

Post a Comment

Subscribe to Post Comments [Atom]

<< Home