2

I am trying to load YML files from a config package, but whenever I use the @Value("${..}") annotation it is null during the @PostConstruct method causing a Null Pointer. I need the @PostConstruct to load all files at once.

  @Value("${my.property.name}")
  private String directoryPath;

  private Map<String, Map<String, List<String>>> entityFiles = new HashMap<>();
  private List<String> fieldsToEnrichByPE = new ArrayList<>();

  @PostConstruct
  public void getFieldsToEnrich() throws IOException {
    ClassLoader cl = this.getClass().getClassLoader();
    ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(cl);
    Resource[] resources = resolver.getResources("classpath*:/" + DIRECTORY_PATH + "*.yml"); // RESOURCES IS NULL
    ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
    for (Resource resource : resources) { // THROWS NULL POINTER BECAUSE RESOURCES NEVER GETS POPULATED, DIRECTORY PATH IS NOT GETTING INSTANTIATED
      File ymlFile = resource.getFile();
      entityFiles.put(ymlFile.getName().replace(".yml", ""), mapper.readValue(ymlFile, Map.class));
    }
  }

Any thoughts on how to alleviate this problem?

Hardcoding directoryPath worked, but if it is hardcoded I am unable to use my test configuration files, as directoryPath is hardcoded to the main resources folder not the test resources folder.

YML File:

my:
  property:
    name: a/b/c/
Beez
  • 478
  • 9
  • 23
  • `my.property.name` is not set. It is as simple as that imo. – Antoniossss Sep 28 '21 at 19:24
  • @Antoniossss it is set in my application.yml – Beez Sep 28 '21 at 19:25
  • Maybe you have typed it there, but that does not mean it is read into the context, nor that you did it correctly. – Antoniossss Sep 28 '21 at 19:26
  • I edited and added into question @Antoniossss -- The thing is PostConstruct is ran before Value variable is instantiated. – Beez Sep 28 '21 at 19:28
  • No, it is not . – Antoniossss Sep 28 '21 at 20:00
  • Can you please include the whole class and not only a snippet? Thanks! – João Dias Sep 28 '21 at 23:57
  • 1
    It cannot be `null`. If it would not resolve the value the application wouldn't even start, you would get an error telling you that a value for property `my.property.name` wasn't found. You don't get that error so you are either not using Spring to instantiate it (doing it yourself) or doing something weird in your application. At least you aren't showing all the code which makes me wonder if this is the code at all. Also is the field `null` (which I doubt) or are you not getting resources? Also if those are somewhere on the file system loading them with `classpath:` will simply not work. – M. Deinum Sep 29 '21 at 05:58
  • Please provide your full class code. In your code I don't where you used `directoryPath` parameter! – ray Sep 29 '21 at 14:59
  • 1
    Did you annotate your class with `@Component` or `@Service` or etc? Because it should be registered as the bean in the spring context. – Faramarz Afzali Sep 29 '21 at 18:00
  • @FaramarzAfzali Posting fix now – Beez Sep 29 '21 at 21:43

2 Answers2

0

Probably you wrote the YML path incorrectly.

Try writing the resolver.getResources("classpath*:/" + DIRECTORY_PATH + "*.yml"); line written directly, to check if the path you made is incorrect.

Maybe even the Java Build path isn't assigned to the correct directory where the YML is placed.

This is the res folder in one of my projects, which is in the Java Build Path

This is the res folder in one of my projects, which is in the Java Buil Path

Those are my guesses, and apologies if im incorrect.

Have a nice day!

Robatortas
  • 16
  • 6
  • 1
    If the value cannot be resolved, the application will simply not start. – M. Deinum Sep 29 '21 at 05:59
  • Oh yeah, my sincerest apologies.. I just saw that. – Robatortas Sep 29 '21 at 06:01
  • YML was configured correctly the problem was that Value gets instantiated AFTER the PostConstruct causing it to be null when the method runs. I got past this by using constructor injection, for the directory path. @Robatortas – Beez Sep 29 '21 at 21:41
  • Well that explains it doesn’t it?! Glad you fixed it! – Robatortas Sep 30 '21 at 02:37
0

The class you are defining the property you are going to read from your properties should contain @Component for Spring to prepare the variable first before executing @PostContruct

import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class TestProp {
    
    @Value("${my.prop.test}")
    private String prop;

    @PostConstruct
    public void postConstructMethod() {
    
    System.out.println("prop= " + prop);
    }
}

Eclipse sysout

  • Following the rules of stackoverflow. It is better to share the full example code in the answer, using a code block, to be a self-contained answer and so it does not rely on links that may break over time – JTejedor Sep 29 '21 at 15:25
  • Thanks, @JTejedor. I fixed and includes the code block. – Paulo Franklim Sep 29 '21 at 16:23
  • @PauloFranklim I had Component on the configuration class. Problem was that Value gets instantiated AFTER the PostConstruct causing it to be null when the method runs. I got past this by using constructor injection, for the directory path. Will post fix shortly. – Beez Sep 29 '21 at 21:42