HiveBrain v1.2.0
Get Started
← Back to all entries
debugjavaspringMinor

Throw exception in Spring when loading a file

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
springfileexceptionloadingwhenthrow

Problem

I have this following piece of code:

@Component
public class ManifestReader {

    private final ServletContext servletContext;
    private Properties p;

    @Autowired
    public ManifestReader(final ServletContext servletContext) {
        this.servletContext = servletContext;
    }

    public Properties getManifest() throws IOException {
        if (p == null) {
            p = new Properties();
            p.load(servletContext.getResourceAsStream("/META-INF/MANIFEST.MF"));
        }
        return p;
    }
}


What I want to do it is just, to load the file, and once it is loaded, it can be injected to all the classes that need that properties file. Like here:

@RestController
@RequestMapping(value = "/info")
public class InfoEndPoint {

    private final ManifestReader manifestReader;

    @Autowired
    public InfoEndPoint(final ManifestReader manifestReader) {
        this.manifestReader = manifestReader;
    }

    @RequestMapping(method = RequestMethod.GET)
    public Info get(final HttpServletRequest httpServletRequest) throws IOException {
        final App app = fillApp(httpServletRequest, manifestReader.getManifest());
        final Info info = new Info();
        info.setApp(app);
        return info;
    }
    ....
}


As you can see, everytime I have to call to getManifest I throw an IOException. I don't really want that since I just need to load it once, and then it can be reused without throwing any exception. So, my idea is that you could call to the getManifest method without having to check for any exception.

My first idea was to load the file in the constructor of the class, but I do not know if that is a good practice for Spring. Any clue?

Solution

My first idea was to load the file in the constructor of the class, but I do not know if that is a good practice for Spring.

It takes the lazy-loading out of the lazy-loader, but then you could ask yourself what the remaining uses of the class are.


As you can see, everytime I have to call to getManifest I throw an IOException.

There are two main ways around this:

  1. Use UncheckedIOException to wrap IOException:



public Properties getManifest() {
      if (p == null) {
        p = new Properties();
        try {
          p.load(servletContext.getResourceAsStream("/META-INF/MANIFEST.MF"));
        } catch (IOException ex) {
          throw new UncheckedIOException(ex);
        }
      }
      return p;
    }


This isn't my preferred approach, because all this does is evade the radar, basically. If you're in a pinch, though, this will do the trick. Mind: UncheckedIOException is not a type of IOException.

(On another note: you probably need to mark p as volatile!)

  1. Move the loading to an initialization method:



public Properties getManifest() {
      return p;
    }

    @PostConstruct
    public void init() throws IOException {
      p = new Properties();
      p.load(servletContext.getResourceAsStream("/META-INF/MANIFEST.MF"));
    }


This approach has the added benefit of being thread-safe: no need to fence access to p, and no risk of having a bean in an inoperable state, or filling the log with errors.

Code Snippets

public Properties getManifest() {
      if (p == null) {
        p = new Properties();
        try {
          p.load(servletContext.getResourceAsStream("/META-INF/MANIFEST.MF"));
        } catch (IOException ex) {
          throw new UncheckedIOException(ex);
        }
      }
      return p;
    }
public Properties getManifest() {
      return p;
    }

    @PostConstruct
    public void init() throws IOException {
      p = new Properties();
      p.load(servletContext.getResourceAsStream("/META-INF/MANIFEST.MF"));
    }

Context

StackExchange Code Review Q#129263, answer score: 2

Revisions (0)

No revisions yet.