Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reading a map from yaml in Java getting null

I am getting a problem in reading my yaml through java, using spring. Let me show the code first

@Component
@EnableConfigurationProperties
@ConfigurationProperties(prefix = "countries")
public class UserLimitReader {

    private HashMap<String, Integer> orders;

    private HashMap<String, Integer> requests;

    public HashMap<String, Integer> getOrders() {
        return orders;
    }

    public void setOrderRedeemableLimit(HashMap<String, Integer>         orders) 
{
        this.orders= orders;
}

public HashMap<String, Integer> getRequests() {
    return requests;
}

public void setMonthlyRedeemableLimit(HashMap<String, Integer> requests) {
    this.requests= requests;
}
}

My yaml file:

cassandra:
    hosts: localhost:9142, 127.0.0.1:9142
    keyspace: test
countries:
    orders:
      JPY: 1000
      USD: 1000
    requests:
      JPY: 100000
      USD: 100000

The spring context xml also has this:

<bean id="yamlProperties"
    class="org.springframework.beans.factory.config.YamlPropertiesFactoryBean">
    <property name="resources">
        <value>classpath:config/application.yaml</value>
    </property>
</bean>

<context:property-placeholder
    properties-ref="yamlProperties" />

Now, the expectation that I have(had) is that, during the runtime of my spring-test application(the context xml is from my test resources, the yaml is also in my test), these values of orders and requests are set, but they are null. Also, note, there are other values in my yaml besides this that I am injecting using @Value(${...}), they are injected absolutely fine!

I looked at this: Spring Boot - inject map from application.yml

I have done virtually the same, but yet, my values are not set. Kindly help.

I was going through google, found this link: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/factory/config/YamlPropertiesFactoryBean.html

In this, it says, everything is read as a string and not a map. Is there any other class that supports reading of Yaml file the way they did it here: Spring Boot - inject map from application.yml

Or is my understanding of YamlPropertiesFactoryBean wrong?

compile 'org.springframework:spring-core:4.2.+'
compile 'org.springframework:spring-beans:4.2.+'
compile 'org.springframework:spring-context:4.2.+'
compile 'org.springframework.boot:spring-boot:1.3.1.RELEASE'
compile 'org.springframework.boot:spring-boot-configuration-processor:1.3.1.RELEASE'

These are the dependencies in gradle. You might be wondering why I have spring-core and spring-boot, essentially, I don't want spring-boot, but without spring-boot, I don't get to add @EnableConfigurationProperties and @ConfigurationProperties, I honestly don't know if I can read the yaml content into a map without them. Hence those two dependencies are added, but if there's a way to remove them, I would be more than happy to remove those two dependencies.

Warm regards, Pavan

like image 629
Pavanraotk Avatar asked Jan 09 '16 18:01

Pavanraotk


1 Answers

I had the same problem with different generic types and I solved it by initializing the map member and remove the setter method, e.g.:

@Component
@EnableConfigurationProperties
@ConfigurationProperties(prefix = "countries")
public class UserLimitReader{
    private Map<String, Integer> orders = new HashMap<>();

    private Map<String, Integer> requests = new HashMap<>();

    public Map<String, Integer> getOrders() {
        return orders;
    }
    ...
}

Please note I used java 7 diamond operator and change the member type to Map instead of HashMap.

IMPORTANT: In my code, I use Spring's configuration class instead of XML and moved the EnableConfigurationProperties to the configuration class. In your case it should be something like:

@Configuration
@EnableConfigurationProperties(value = {UserLimitReader.class})
public class SpringConfiguration {
    ...
}

@ConfigurationProperties(prefix = "countries", locations: "classpath:config/application.yaml")
public class UserLimitReader {
    ...
}

Don't know how you configure it using XML, however as I wrote in my comments I still think you should make sure Spring's finds your class using component scan or something alike.

@Value work as Spring loads the YAML file without any problem using your context file, however it does not mean UserLimitReader file is loaded and configured by Spring.

like image 123
Koby Avatar answered Sep 23 '22 18:09

Koby