I have int, float, boolean and string from Properties file. Everything has loaded in Properties. Currently, I am parsing values as I know expected value for particular key.
Boolean.parseBoolean("false");
Integer.parseInt("3")
What is better way of setting these constants values, If I don't know what could be primitive value datatype for a key.
public class Messages {
Properties appProperties = null;
FileInputStream file = null;
public void initialization() throws Exception {
appProperties = new Properties();
try {
loadPropertiesFile();
} catch (Exception e) {
throw new Exception(e.getMessage(), e);
}
}
public void loadPropertiesFile() throws IOException {
String path = "./cfg/message.properties";
file = new FileInputStream(path);
appProperties.load(file);
file.close();
}
}
Properties File.
messassge.properties
SSO_URL = https://example.com/connect/token
SSO_API_USERNAME = test
SSO_API_PASSWORD = Uo88YmMpKUp
SSO_API_SCOPE = intraday_api
SSO_IS_PROXY_ENABLED = false
SSO_MAX_RETRY_COUNT = 3
SSO_FLOAT_VALUE = 3.0
Constant.java
public class Constants {
public static String SSO_URL = null;
public static String SSO_API_USERNAME = null;
public static String SSO_API_PASSWORD = null;
public static String SSO_API_SCOPE = null;
public static boolean SSO_IS_PROXY_ENABLED = false;
public static int SSO_MAX_RETRY_COUNT = 0;
public static float SSO_FLOAT_VALUE = 0;
}
If you have a class of configuration values, like your Constants class, and you want to load all values from a configuration (properties) file, you can create a little helper class and use reflection:
public class ConfigLoader {
public static void load(Class<?> configClass, String file) {
try {
Properties props = new Properties();
try (FileInputStream propStream = new FileInputStream(file)) {
props.load(propStream);
}
for (Field field : configClass.getDeclaredFields())
if (Modifier.isStatic(field.getModifiers()))
field.set(null, getValue(props, field.getName(), field.getType()));
} catch (Exception e) {
throw new RuntimeException("Error loading configuration: " + e, e);
}
}
private static Object getValue(Properties props, String name, Class<?> type) {
String value = props.getProperty(name);
if (value == null)
throw new IllegalArgumentException("Missing configuration value: " + name);
if (type == String.class)
return value;
if (type == boolean.class)
return Boolean.parseBoolean(value);
if (type == int.class)
return Integer.parseInt(value);
if (type == float.class)
return Float.parseFloat(value);
throw new IllegalArgumentException("Unknown configuration value type: " + type.getName());
}
}
Then you call it like this:
ConfigLoader.load(Constants.class, "/path/to/constants.properties");
You can extend the code to handle more types. You can also change it to ignore missing properties, instead of failing like it does now, such that assignments in the field declaration will remain unchanged, i.e. be the default.
If you know the type of constant, you can use Apache Commons Collections.
For example, you can use some utilities method based on type of your constant.
booelan SSO_IS_PROXY_ENABLED = MapUtils.getBooleanValue(appProperties, "SSO_IS_PROXY_ENABLED", false);
String SSO_URL = MapUtils.getString(appProperties, "SSO_URL", "https://example.com/connect/token");
You can even use default values to avoid errors.
Dambros is right, every thing you store inside a Properties file is as a String value.
You can track your different primitive data types after retrieving properties value as below like ref. -
Java Properties File: How to Read config.properties Values in Java?
package crunchify.com.tutorial;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.Properties;
/**
* #author Crunchify.com
*
*/
public class CrunchifyGetPropertyValues {
String result = "";
InputStream inputStream;
public String getPropValues() throws IOException {
try {
Properties prop = new Properties();
String propFileName = "config.properties";
inputStream = getClass().getClassLoader().getResourceAsStream(propFileName);
if (inputStream != null) {
prop.load(inputStream);
} else {
throw new FileNotFoundException("property file '" + propFileName + "' not found in the classpath");
}
Date time = new Date(System.currentTimeMillis());
// get the property value and print it out
String user = prop.getProperty("user");
String company1 = prop.getProperty("company1");
String company2 = prop.getProperty("company2");
String company3 = prop.getProperty("company3");
result = "Company List = " + company1 + ", " + company2 + ", " + company3;
System.out.println(result + "\nProgram Ran on " + time + " by user=" + user);
} catch (Exception e) {
System.out.println("Exception: " + e);
} finally {
inputStream.close();
}
return result;
}
}
and later convert to primitive -
How to convert String to primitive type value?
I suggest you to track your data types value by putting the key values inside String type switch statement and later retrieve the related data type value by using key name cases.
String type switch case is possible after Java 7.
Not entirely sure whether I exactly understand the problem but a possibility could be to include the type of the property value in the (String) value. So for example the properties you showed would become something like:
SSO_URL = URL:https://example.com/connect/token
SSO_API_USERNAME = STRING:test
SSO_API_PASSWORD = STRING:Uo88YmMpKUp
SSO_API_SCOPE = STRING:intraday_api
SSO_IS_PROXY_ENABLED = BOOLEAN:false
SSO_MAX_RETRY_COUNT = INTEGER:3
SSO_FLOAT_VALUE = FLOAT:3.0
During the parsing of the property values you first determine the type of the property by looking at the part before : and use the part after for the actual parsing.
private static Object getValue(Properties props, String name) {
String propertyValue = props.getProperty(name);
if (propertyValue == null) {
throw new IllegalArgumentException("Missing configuration value: " + name);
} else {
String[] parts = string.split(":");
switch(parts[0]) {
case "STRING":
return parts[1];
case "BOOLEAN":
return Boolean.parseBoolean(parts[1]);
....
default:
throw new IllegalArgumentException("Unknown configuration value type: " + parts[0]);
}
}
}
Follow the dropwizard configuration pattern where you define your constants using YAML instead of Properties and use Jackson to deserialize it into your Class. Other than type safety, dropwizard's configuration pattern goes one step further by allowing Hibernate Validator annotations to validate that the values fall into your expected ranges.
For dropwizard's example...
http://www.dropwizard.io/0.9.2/docs/getting-started.html#creating-a-configuration-class
For more information about the technology involved...
github.com/FasterXML/jackson-dataformat-yaml
hibernate.org/validator/
Spring Boot has ready to use and feature reach solution for type-safe configuration properties.
Definitely, use of the Spring just for this task is overkill but Spring has a lot of cool features and this one can attract you to right side ;)
You can define your configurable parameters as 'static' in your class of choice, and from a static init call a method that loads the parameter values from a properties file.
For example:
public class MyAppConfig {
final static String propertiesPath="/home/workspace/MyApp/src/config.properties";
static String strParam;
static boolean boolParam;
static int intParam;
static double dblParam;
static {
// Other static initialization tasks...
loadParams();
}
private static void loadParams(){
Properties prop = new Properties();
try (InputStream propStream=new FileInputStream(propertiesPath)){
// Load parameters from config file
prop.load(propStream);
// Second param is default value in case key-pair is missing
strParam=prop.getProperty("StrParam", "foo");
boolParam=Boolean.parseBoolean(prop.getProperty("boolParam", "false"));
intParam= Integer.parseInt(prop.getProperty("intParam", "1"));
dblParam=Double.parseDouble(prop.getProperty("dblParam", "0.05"));
} catch (IOException e) {
logger.severe(e.getMessage());
e.printStackTrace();
}
}
}
This might help:
props.getProperty("name", Integer.class);
Related
I'm creating a little java app and I'm trying to load the yml files based on config.yml lang set (en/it) but I can't find a way to load them, only the last one in an array is loaded which is "it" for me.
I know that my method is probably the worst solution for a language file, I'm open to every method that will help me with the problem. But I prefer an external lang_en/it file instead of internal ones (Or is it better internal?)
After I set the language, the app will self-update every text in every class.
static final Properties props = new Properties();
static WelcomeMessage main = new WelcomeMessage();
static File file = null;
static File folder = null;
static boolean os = main.os.startsWith("Windows");
public static void create() {
String[] lang = {"en", "it"};
for (String s : lang) {
file = new File(WelcomeMessage.user + "/AppData/Roaming/MyApp/lang_" + s + ".yml");
folder = new File(file.getParent());
SetLanguages(s);
}
if (!file.exists()) {
try {
if (os) {
folder.mkdir();
file.createNewFile();
} else {
file = new File(main.user + "/Library/Application Support/MyApp/config.yml");
folder.mkdir();
file.createNewFile();
}
} catch (Exception e) {
System.out.println(e + " " + file);
}
}
}
public static void SetLanguages(String lang) {
if (lang.equals("en")) {
store("Settings.Save", "Save");
store("Settings.ConfigPath", "Config Path");
store("Settings.Language", "Language");
store("Settings.Title", "Settings");
} else if (lang.equals("it")) {
store("Settings.Save", "Salva");
store("Settings.ConfigPath", "Percorso config");
store("Settings.Language", "Lingua");
store("Settings.Title", "Impostazioni");
}
}
public static String get(String value) {
String key = null;
try {
FileInputStream in = new FileInputStream(file);
props.load(in);
key = props.getProperty(value);
in.close();
} catch (Exception fnf) {
System.out.println(fnf);
}
return key;
}
public static void store(String value, String key) {
try {
FileOutputStream out = new FileOutputStream(file);
props.setProperty(value, key);
props.store(out, null);
out.close();
} catch (Exception fnf) {
System.out.println(fnf);
}
}
This is how I get a text from yml:
path.setText(Language.get("Settings.ConfigPath"));
language.setText(Language.get("Settings.Language"));
f.setTitle(Language.get("Settings.Title"));
save.setText(Language.get("Settings.Save"));
And this my Language.get(key)
public static String get(String value) {
String key = null;
try {
FileInputStream in = new FileInputStream(file);
props.load(in);
key = props.getProperty(value);
in.close();
} catch (Exception fnf) {
System.out.println(fnf);
}
return key;
}
I suggest the following changes:
Create a Settings class to hold the properties save, configPath, language and title. Even better if this class uses an immutable builder pattern, because once set, the properties will never change.
Create a SettingsFactory class with method getSettings(language). This class shall also have a field Map<String, Settings>. In the constructor (or a static block), first check if a file exists on the disk, and if yes, load it into the map. If not, populate the map, one entry for each language, and persist to the disk.
getSettings would simply return the value from the map corresponding to the given language.
The format of the file written to the disk is a different matter. You say YAML, but I'm not seeing any YAML specific code in your snippet. If you don't know how to write a map to YAML, open a different question.
I'm using UNIVOCITY-PARSERS for converting csv file rows into java objects.
while processing the file, if it encounters any problem any of the column in row, then it parsing getting stopped in that row and throwing exception. But i need something which will continue till end of the file just by skipping the row which has error. But i didn't any utility classes in the api.
MY Bean class
public class ItemcodeBean {
#Trim
#NullString(nulls = { " ", "" })
#Parsed(field = "ItemCode")
private String itemCode;
#Trim
#NullString(nulls = { " ", "" })
#Parsed(field = "PartNumber")
private String partNumber;
#Trim
#NullString(nulls = { " ", "" })
#Parsed(field = "ModelNumber")
private String modelNumber;
}
My Main Class
public class TestClass {
private BeanListProcessor<ItemcodeBean>
rowProcessor = null;
private CsvParser parser = null;
public static void main(String[] args) {
TestClass testClass = new TestClass();
testClass.init();
try{
ItemcodeBean itemcodeBean;
while ((itemcodeBean = testClass.getRowData()) != null){
System.out.println(itemcodeBean.toString());
}
}catch (Throwable ex){
System.out.println(ex.getLocalizedMessage());
}
}
private BeanListProcessor<ItemcodeBean> init() {
// BeanListProcessor converts each parsed row to an instance of a given class, then stores each instance into a list.
this.rowProcessor =
new BeanListProcessor<ItemcodeBean>(ItemcodeBean.class);
CsvParserSettings parserSettings = new CsvParserSettings();
parserSettings.setProcessor(rowProcessor);
parserSettings.setHeaderExtractionEnabled(true);
// skip leading whitespaces
parserSettings.setIgnoreLeadingWhitespaces(true);
//skip trailing whitespaces
parserSettings.setIgnoreTrailingWhitespaces(true);
//skip empty lines
parserSettings.setSkipEmptyLines(true);
File file = new File("C:\\Users\\abhishyam.c\\Downloads\\Itemcode_Template.csv");
this.parser = new CsvParser(parserSettings);
//parser.parse(file);
parser.beginParsing(file);
return rowProcessor;
}
private ItemcodeBean getRowData() throws Throwable {
String[] row;
try {
while ((row = parser.parseNext()) != null){
return rowProcessor.createBean(row, parser.getContext());
}
}catch (DataProcessingException e){
throw new DataProcessingException(e.getColumnName(),e);
}
// parser.stopParsing();
return null;
}
}
Just use an error handler and it will keep going unless you throw the exception yourself:
//Let's set a RowProcessorErrorHandler to log the error. The parser will keep running.
settings.setProcessorErrorHandler(new RowProcessorErrorHandler() {
#Override
public void handleError(DataProcessingException error, Object[] inputRow, ParsingContext context) {
println(out, "Error processing row: " + Arrays.toString(inputRow));
println(out, "Error details: column '" + error.getColumnName() + "' (index " + error.getColumnIndex() + ") has value '" + inputRow[error.getColumnIndex()] + "'");
}
});
UPDATE: You can prevent the row to be discarded by using a RetryableErrorHandler instead. This is a special implementation added to version 2.3.0, and allows the user to call the methods setDefaultValue() to assign a value to the problematic column, and keepRecord to prevent the record from being discarded.
Example:
settings.setProcessorErrorHandler(new RetryableErrorHandler<ParsingContext>() {
#Override
public void handleError(DataProcessingException error, Object[] inputRow, ParsingContext context) {
//if there's an error in the first column, assign 50 and proceed with the record.
if (error.getColumnIndex() == 0) {
setDefaultValue(50);
} else { //else keep the record anyway. Null will be used instead.
keepRecord();
}
}
});
Note that if error.getColumnIndex() returns -1, there's nothing that can be done to save the record, and it will be skipped regardless. You can use this to log the error details.
In properties file i have 50 questions.
Quest1=1.1
Quest1Text=How are ju?
Quest2=1.2
Quest2Text=How are jui?
Quest3=1.3
Quest3Text=How are juieeeeee?
I want to read them in Java and display in JSP.
Standard way on internet is #Value(ques2)variable #Value(quest2Text) variable
But this will make my controller hauch-pauch.
Could you please tell how to assign values to a list in java from properties file using some Spring Annotation?
First, you have add property file into your context configuration:
#PropertySource(name = "questions", value = "classpath:question.properties")
public class AppConfig {
...
}
I used classpath:prefix in example(that means file will be located in root of class path), but you can use file:, to specify absolute path. Note, that name of source is specified as questions. We will need it in future.
Second, create data container class. Of course, you can use Map<String, String> to store your questions, but class will be more convenient:
public class Quest{
private String number;
private String text;
//getters and setters
....
}
Third, get property source in controller and load numbers and values:
#Controller
public class MyController {
#Autowired
private ConfigurableEnvironment environment;
#RequestMapping("/mymapping")
public String method(ModelMap model){
List<Quest> questList = loadQuestList();
model.addAttribute("questList", questList);
return "myview";
}
private List<Quest> loadQuestList(){
ResourcePropertySource source =
(ResourcePropertySource)environment.getPropertySources().get("questions");
//first get all names of questions like 'Quest1','Quest2' etc
List<String> nameList = new ArrayList<String>();
for(String name : source.getPropertyNames()){
if(!name.endsWith("Text")){
nameList.add(name);
}
}
//unfortunately, default properties are unsorted. we have to sort it
Collections.sort(nameList);
//now, when we have quest names, we can fill list of quests
List<Quest> list = new ArrayList<Quest>();
for(String name : nameList){
String number = source.getProperty(name);
String text = source.getProperty(name+"Text");
Quest quest = Quest();
quest.setNumber(number);
quest.setText(text);
list.add(quest);
}
return list;
}
}
You can do one thing, all the keys 'QuestX' combine in single key 'Quest' by separating them with some delimiter. Similarly for all the keys starting with 'QuestXText' into another key like 'QuestText'.
Then you can use :
#Value("#{'${Quest}'.split(',')}")
private List<String> Quest;
#Value("#{'${QuestText}'.split(',')}")
private List<Integer> QuestText;
Or you can go with another approach as follows :
public static List<String> getPropertyList(Properties properties, String name)
{
List<String> result = new ArrayList<String>();
for (Map.Entry<Object, Object> entry : properties.entrySet())
{
if (((String)entry.getKey()).matches("^" + Pattern.quote(name) + "\\.\\d+$"))
{
result.add((String) entry.getValue());
}
}
return result;
}
For more clarity refer :
https://stackoverflow.com/a/18654272/3226981
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class Ex {
public static void main(String[] args) {
Properties prop = new Properties();
InputStream input = null;
`enter code here`List<String> values=new ArrayList<>();
try {
input = new FileInputStream("/application.properties");
prop.load(input);
for (int i = 1; i < 50; i++) {
System.out.println(prop.getProperty("Quest" + i));
values.add(prop.getProperty("Quest" + i));
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
Hi I have a class ReadProperty which has a method ReadPropertyFile of return type Myclass which read the parameter values from a property file and return Myclass object. I need help to test the ReadPropertyFile method with JUnit, if possible with mock files and mock object.
Here is my code.
import java.io.FileInputStream;
import java.util.Properties;
public class ReadProperty {
public Myclass ReadPropertyFile(String fileName) {
Myclass myclass = null;
String testparam = null;
FileInputStream fis = null;
Properties prop = new Properties();
try {
fis = new FileInputStream(fileName);
try {
prop.load(fis);
System.out.println("Load Property file : Success !");
} catch (Exception ex) {
System.out.println("Load Property file : Exception : " + ex.toString());
}
/*
* loading the properties
*/
try {
testparam = prop.getProperty("testparam");
System.out.println("testparam Type : " + testparam);
} catch (Exception ex) {
System.out.println("testparam Type : " + ex.toString());
}
} catch (Exception ex) {
ex.printStackTrace();
System.out.println("Property file read fail : " + ex.toString());
System.exit(1);
}
Myclass = new Myclass(testparam);
return Myclass;
} }
I don't think that you really need to mock anything here. You want to test if your property reader is able to access and read a file as you expect, so test exactly that. For regular properties it can go like this:
#Test
public void shouldReadPropFileFromSingleString() {
final Properties p = PropertiesLoader
.loadProperties("propfile");
assertNotNull(p);
assertFalse(p.isEmpty());
for (final Entry<Object, Object> e : p.entrySet()) {
assertEquals(expectedProperties.get(e.getKey()), e.getValue());
}
}
For your case, you can adapt it:
#Test
public void shouldReadCorrectProp() {
final MyClass p = ReadProperty
.readPropertyFile("propfile");
assertNotNull(p);
assertEquals(expectedProperty, p);
}
You may also want to test the sad path - what happens if the property file is not found, are any fallback properties available etc.
BTW, I would advise changing the method name, since reading a property file is not the primary concern of your method - retrieving a property is. Better yet, decompose the method into a getProperty and a readPropertyFile method, where the first method calls the second. So you will have a cleaner design according to Separaton of Concerns
I've a swing application that has to connect to database for some resources, for this i used .properties file to store database properties and that can be read at runtime.
For this i am using the following code
public void readPropertiesFile(){
try{
InputStream is = ReadValues.class.getResourceAsStream(PROP_FILE);
Properties prop = new Properties();
prop.load(is);
String URL = prop.getProperty("DB_URL");
String user = prop.getProperty("DB_USER");
String pwd = prop.getProperty("DB_PWD");
is.close();
/* code to use values read from the file*/
}catch(Exception e){
System.out.println("Failed to read from " + PROP_FILE + " file.");
}
}
but i've to call this method whenever i want to connect to the database (for Connection object).
I know the thing that now processing is fast enough to run these lines in micro seconds, but it's for my own knowledge that suggest me the ways through which i can store these DB values when application starts or the first time user try to connect to DB for any operation in such objects or variables or constants that will be usable until the application restarts and can be called directly without reading the file.
P.S. : I know that the DB values will not change oftentimes, and if it happens than i'll be happy to restart my application :)
by making these static fields in a separate class, they will not be loaded until the first time you access URL,USER, or PASSWORD.
public class DbProps {
public static final String URL;
public static final String USER;
public static final String PASSWORD;
static {
try{
InputStream is = ReadValues.class.getResourceAsStream(PROP_FILE);
try {
Properties prop = new Properties();
prop.load(is);
URL = prop.getProperty("DB_URL");
USER = prop.getProperty("DB_USER");
PASSWORD = prop.getProperty("DB_PWD");
} finally {
is.close();
}
}catch(Exception e){
throw new RuntimeException("Failed to read from " + PROP_FILE + " file.", e);
}
}
}
You can nake a check condition which will check if it is first time then set the value other wise use the existing value
public static boolean isFirstTime = true;
public static String URL = true;
public static String user = true;
public static String pwd = true;
public void readPropertiesFile(){
if(isFirstTime){
try{
InputStream is = ReadValues.class.getResourceAsStream(PROP_FILE);
Properties prop = new Properties();
prop.load(is);
URL = prop.getProperty("DB_URL");
user = prop.getProperty("DB_USER");
pwd = prop.getProperty("DB_PWD");
isFirstTime = false;
is.close();
/* code to use values read from the file*/
}catch(Exception e){
System.out.println("Failed to read from " + PROP_FILE + " file.");
}
}
}
//use this URL user and pwd in your application
Here's a generic environment class for you. You can get your DB props like Environment.getEnvironment().getProperty("DB_URL"), etc.
public class Environment {
private static final String PROP_FILE = "somefilename";
private static final Environment singleton = new Environment();
public static Environment getEnvironment() {
return singleton;
}
private Properties properties = new Properties();
protected Environment() {
super();
loadProperties();
}
public Properties getProperties() {
return properties;
}
public String getProperty(String propertyName) {
return getProperty(propertyName, System.getProperty(propertyName));
}
public String getProperty(String propertyName, String defaultValue) {
return getProperties().getProperty(propertyName, defaultValue);
}
public void loadProperties() {
URL resourceURL = null;
try {
resourceURL = Thread.currentThread().getContextClassLoader()
.getResource(PROP_FILE);
getProperties().load(resourceURL.openStream());
System.out.println("Loaded properties from "
+ resourceURL.toExternalForm());
} catch (IOException ioe) {
System.err.println("Failed to load properties from "
+ resourceURL.toExternalForm());
}
}
}