21

I have a static util class that does some string manipulation on a bit sensitive data. Prior to use of this class I need to initialize certain static variables with values, such as usernames/password, that I prefer to store in a .properties file.

I am not very familiar with how loading of .properties file work in Java, especially outside of *Spring DI *container. Anyone can give me a hand/insight on how this can be done?

Thank you!

Addition: .properties file precise location is unknown, but it will be on the classpath. Sorta like classpath:/my/folder/name/myproperties.propeties

Tamir Vered
  • 10,187
  • 5
  • 45
  • 57
xelurg
  • 4,294
  • 9
  • 35
  • 37
  • You mention Spring - do you use the framework in the application that incorporates this static utility class? – teabot Jun 25 '09 at 16:29
  • well, it is a bit weird. class will be used inside an app that uses spring container. class itself however won't be wired in using spring, it needs to be just a static utility class that get's called by worker threads that are wired by Spring. I can modify worker threads, but I can't modify wiring of those threads(so I can't use PropertyPlaceHolderConfigurer)...hm, does it make any sense? :) – xelurg Jun 25 '09 at 16:35

8 Answers8

29

First, obtain an InputStream from which the properties are to be loaded. This can come from a number of locations, including some of the most likely:

  • A FileInputStream, created with a file name that is hard-coded or specified via a system property. The name could be relative (to the current working directory of the Java process) or absolute.
  • A resource file (a file on the classpath), obtained through a call to getResourceAsStream on the Class (relative to the class file) or ClassLoader (relative to the root of the class path). Note that these methods return null if the resource is missing, instead of raising an exception.
  • A URL, which, like a file name, could be hard-coded or specified via a system property.

Then create a new Properties object, and pass the InputStream to its load() method. Be sure to close the stream, regardless of any exceptions.

In a class initializer, checked exceptions like IOException must be handled. An unchecked exception can be thrown, which will prevent the class from being initialized. That, in turn, will usually prevent your application from running at all. In many applications, it might be desirable to use default properties instead, or fallback to another source of configuration, such as prompting a use in an interactive context.

Altogether, it might look something like this:

private static final String NAME = "my.properties";

private static final Properties config;

static {
  Properties fallback = new Properties();
  fallback.put("key", "default");
  config = new Properties(fallback);

  URL res = MyClass.getResource(NAME);
  if (res == null) throw new UncheckedIOException(new FileNotFoundException(NAME));
  URI uri;
  try { uri = res.toURI(); }
  catch (URISyntaxException ex) { throw new IllegalArgumentException(ex); }

  try (InputStream is = Files.newInputStream(Paths.get(uri))) { config.load(is); } 
  catch (IOException ex) { throw new UncheckedIOException("Failed to load resource", ex); }
}
erickson
  • 265,237
  • 58
  • 395
  • 493
6
  1. Check out java.util.Properties.

  2. You can use a static initializer. So on the top of the class you can do:


 static {
    Properties props = new Properties();
    InputStream steam = ...; // open the file
    props.load(stream);

    // process properties content
    String username = props.getProperty("username");
  }
notnoop
  • 58,763
  • 21
  • 123
  • 144
  • Sorry, I guess you were already formatting the code while I was doing it. – Michael Myers Jun 25 '09 at 16:34
  • 2
    You may need some exception handling, since I don't think exceptions can be thrown from within a static block. – Peter Jun 25 '09 at 16:41
  • 1
    RuntimeExceptions can be thrown from within a static block. You will need to handle checked exceptions for the file operations. – akf Jun 25 '09 at 16:49
  • 1
    The suggested implementation here was meant mainly for illustration. To make it production quality, you need to handle exceptions related to the file (e.g. security, existence, IOException), closing the connection within a finally block, handling encryption (I hope that he doesn't keep passwords in plaintext), etc – notnoop Jun 25 '09 at 17:10
3

Use either:

CurrentClassName.class.getResourceAsStream 
new FileInputStream(File)

to get the input stream depending on if the class is in or out of the classpath. Then use

Properties.load

to load the properties.

gizmo753
  • 63
  • 2
  • 8
stevedbrown
  • 8,862
  • 8
  • 43
  • 58
1

It's been a while, but if I remember correctly you just do something like this:

Properties prop = new Properties();
prop.load(new FileInputStream(filename));

//For each property you need.
blah = prop.getProperty(propertyname);
Carl Manaster
  • 39,912
  • 17
  • 102
  • 155
patros
  • 7,719
  • 3
  • 28
  • 37
1

Well with static Properties it would make sense to initialize them as a Singleton which will be loaded once in a class. Here's an example:

class Example
{
    public final static String PROPSFILE = "test.properties";

    private static Properties props;

    protected static Properties getProperties()
    {
        if(props == null)
        {
            props = new Properties();
            props.load(new FileInputStream(new File(PROPSFILE));
        }
        return props;
    }

    public static User getUser()
    {
        String username = getProperties().getProperty("username");
        return new User(username);
    }
}

If you use relative Pathnames you should make sure, that your classpath is setup righ.

Daff
  • 43,734
  • 9
  • 106
  • 120
  • 3
    That's not a Singleton. It is simply a static variable and method. The question didn't require public access to the properties, but initialization of static members from a properties file. – Robin Jun 25 '09 at 16:44
  • Well personally I'm not a Fan of static Initialisation because it caused some trouble in a Project I was working on. I would recommend to use at least static Factory Methods where ever possible (I updated the example for that). But true, that wasn't actually the question. – Daff Jun 25 '09 at 17:14
1

for me MyClass.class.getClassLoader().getResourceAsStream(..) did the trick:

private static final Properties properties;

static {
    Properties fallback = new Properties();
    fallback.put(PROP_KEY, FALLBACK_VALUE);

    properties = new Properties(fallback);

    try {
        try (InputStream stream = MyClass.class.getClassLoader().getResourceAsStream("myProperties.properties")) {
            properties.load(stream);
        }
    } catch (IOException ex) {
        // handle error
    }
}
electrobabe
  • 1,549
  • 18
  • 17
0

I agree with @Daff, maybe better to use singleton class...this what i have on my project for similar requirement, maybe it may help:

clients of the class can use it like this:

ConfigsLoader configsLoader = ConfigsLoader.getInstance("etc/configs.xml");

System.out.format("source dir %s %n", configsLoader.getSourceDir());

and then the class:

public class ConfigsLoader {

private String sourceDir;
private String destination;
private String activeMqUrl;

private static Logger log = Logger.getLogger(ConfigsLoader.class.getName());

private static ConfigsLoader instance = null;

private ConfigsLoader(String configFileName) {
    log.info("loading configs");
    Properties configs = new Properties();
    try {
        configs.loadFromXML(new FileInputStream(configFileName));

        sourceDir = configs.getProperty("source.dir");
        destination = configs.getProperty("destination");
        activeMqUrl = configs.getProperty("activemqconnectionurl");
        configs.setProperty("lastLoaded", new SimpleDateFormat("yyyy-M-d HH:mm").format(new Date()));
        configs.storeToXML(new FileOutputStream(configFileName), "saving last modified dates");

    } catch (InvalidPropertiesFormatException e) {
        log.log(Level.SEVERE,"Error occured loading the properties file" ,e);
    } catch (FileNotFoundException e) {
        log.log(Level.SEVERE,"Error occured loading the properties file" ,e);
    } catch (IOException e) {
        log.log(Level.SEVERE,"Error occured loading the properties file" ,e);
    }
}

public static ConfigsLoader getInstance(String configFileName) {
    if(instance ==null) {
        instance = new ConfigsLoader(configFileName);
    }

    return instance;
}

public String getSourceDir() {
    return sourceDir;
}

public void setSourceDir(String sourceDir) {
    this.sourceDir = sourceDir;
}

public String getDestination() {
    return destination;
}

public void setDestination(String destination) {
    this.destination = destination;
}

public String getActiveMqUrl() {
    return activeMqUrl;
}

public void setActiveMqUrl(String activeMqUrl) {
    this.activeMqUrl = activeMqUrl;
}

}

Mosd
  • 1,640
  • 19
  • 22
0

I did this finally using getResourceAsStream() fuction associated with the class in which the static code block is being written.

//associate Property and ImputStream imports
public class A {
    static Properties p;
    static {
      p = new Properties();
      try {
          InputStream in = A.class.getResourceAsStream("filename.properties");
          p.load(in);
      } catch (FileNotFoundException e) {
        System.out.println("FileNotFoundException");
        e.printStackTrace();
      } catch (IOException e) {
        System.out.println("IOException");
        e.printStackTrace();
      }
    }
    .
    .
    .
}
kung_fu_coder
  • 146
  • 2
  • 3