Получить int, float, boolean и string из свойств

У меня есть int, float, boolean и string из файла свойств. В свойствах все загрузилось. В настоящее время я анализирую значения, поскольку знаю ожидаемое значение для определенного ключа.

Boolean.parseBoolean("false");
Integer.parseInt("3")

Какой лучший способ установить значения этих констант, если я не знаю, что может быть типом данных примитивного значения для ключа.

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();
    }
}

Файл свойств. сообщения

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

Константа.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;
}

person Pratiyush Kumar Singh    schedule 19.04.2016    source источник
comment
Проблема в том, что все является строкой в ​​файле свойств. Если вы не хотите использовать исключения и пробовать каждый анализ вручную (что ужасно), я не понимаю, как вы можете что-то анализировать автоматически. В конце концов, что означают строки 3 или false для компилятора? Ничего...   -  person dambros    schedule 19.04.2016
comment
что вы имеете в виду, говоря, что я не знаю, что может быть ключом и значением? твой вопрос не ясен   -  person Nicolas Filotto    schedule 19.04.2016
comment
Что ж, подумав еще раз, если вы хотите анализировать только логические значения, int и double, это можно сделать, используя комбинацию регулярных выражений (для проверки и поиска типа) + отражение (для заполнения константы). Я думаю, что это немного лучше, чем использование исключений.   -  person dambros    schedule 19.04.2016
comment
Dambros, это может быть одним из решений для использования регулярных выражений. У меня возникла идея создать другой файл свойств для разных примитивов, тогда он будет безопасным для типов.   -  person Pratiyush Kumar Singh    schedule 19.04.2016
comment
Вам определенно нужны метаданные о типах данных свойств в файле свойств. Что, если кто-то добавит еще одно свойство IS_ENABLED = true, и ваша логика автоматически преобразует его в boolean, но фактическая логика в коде, использующем это свойство, рассматривает его как String.   -  person Siddharth    schedule 28.04.2016


Ответы (8)


Если у вас есть класс значений конфигурации, например класс Constants, и вы хотите загрузить все значения из файла конфигурации (свойств), вы можете создать небольшой вспомогательный класс и использовать отражение:

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());
    }
}

Затем вы называете это так:

ConfigLoader.load(Constants.class, "/path/to/constants.properties");

Вы можете расширить код для обработки большего количества типов. Вы также можете изменить его, чтобы игнорировать отсутствующие свойства, а не сбой, как сейчас, чтобы назначения в объявлении поля оставались неизменными, то есть по умолчанию.

person Andreas    schedule 19.04.2016
comment
Хорошее решение. Но это не работает, когда я добавляю final в константы. Он отлично работает, когда я устанавливаю Accessible true и setInt с двумя полями параметров, field.getModifiers() и ~Modifier.FINAL. - person Pratiyush Kumar Singh; 27.04.2016
comment
@PratiyushKumarSingh, вы никогда не упоминали в своем вопросе, что константы могут быть окончательными, ИМХО, это явно лучший вариант, который у вас есть на сегодняшний день. - person Nicolas Filotto; 29.04.2016
comment
@PratiyushKumarSingh, если вы пометите свои поля как final и инициализируете их, вы не сможете их изменить в соответствии с JLS. - person Matthieu; 30.04.2016
comment
@PratiyushKumarSingh, но если вы не хотите делать их public, отметьте их private и используйте методы public static getXXX(). - person Matthieu; 30.04.2016

Если вы знаете тип константы, вы можете использовать коллекции Apache Commons.

Например, вы можете использовать какой-либо метод утилит, основанный на типе вашей константы.

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");

Вы даже можете использовать значения по умолчанию, чтобы избежать ошибок.

person josivan    schedule 19.04.2016
comment
Правда, он отлично работает, если мы знаем тип данных примитива. Но мы не можем жестко закодировать или написать код для 100 таких значений свойств. - person Pratiyush Kumar Singh; 19.04.2016
comment
@PratiyushKumarSingh Почему вы не можете жестко закодировать тип данных, когда вам нужно жестко закодировать тип? Например. SSO_URL определен как String (жестко запрограммированный), поэтому вызовите getString() (соответствующий жесткий код). - person Andreas; 19.04.2016
comment
Да, Андреас, сейчас я этим занимаюсь, и это не похоже на оптимизированное решение. - person Pratiyush Kumar Singh; 19.04.2016

Дамброс прав, все, что вы храните в файле свойств, представляет собой строковое значение. Вы можете отслеживать различные примитивные типы данных после получения значения свойств, как показано ниже, например ref. -

Файл свойств Java: как читать конфигурацию Значения .properties в 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;
    }
}

а затем преобразовать в примитив - Как преобразовать Строка в значение примитивного типа?

Я предлагаю вам отслеживать значение ваших типов данных, помещая значения ключей в оператор переключения типа String, а затем извлекая значение связанного типа данных, используя регистры имени ключа. Случай переключения строкового типа возможен после Java 7.

person ArifMustafa    schedule 19.04.2016
comment
Да, это тоже возможное решение. Ознакомьтесь с идеей, предложенной Dambros, также мы можем использовать разные файлы для примитивов, таких как int_message.properties , string_messge.properties ... и так далее. - person Pratiyush Kumar Singh; 19.04.2016

Не совсем уверен, правильно ли я понимаю проблему, но можно было бы включить тип значения свойства в значение (String). Так, например, свойства, которые вы показали, станут чем-то вроде:

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

Во время синтаксического анализа значений свойств вы сначала определяете тип свойства, просматривая часть до : и используете часть после для фактического синтаксического анализа.

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]);
        }
    }
 }
person uniknow    schedule 28.04.2016

Следуйте шаблону конфигурации dropwizard, где вы определяете свои константы, используя YAML вместо свойств, и используете Jackson для десериализации их в свой класс. Помимо безопасности типов, шаблон конфигурации dropwizard делает еще один шаг вперед, позволяя аннотациям Hibernate Validator проверять, попадают ли значения в ожидаемые диапазоны.

Для примера dropwizard...

Для получения дополнительной информации о задействованной технологии...

  • github.com/FasterXML/jackson-dataformat-yaml
  • hibernate.org/validator/
person Carlos Herrera    schedule 30.04.2016

Spring Boot имеет готовое к использованию и расширенное решение для безопасная конфигурация.

Определенно, использование Spring только для этой задачи — это излишество, но у Spring есть много интересных функций, и это может привлечь вас к нужной стороне ;)

person Andrew Kolpakov    schedule 29.04.2016

Вы можете определить свои настраиваемые параметры как «статические» в выбранном вами классе и из статического вызова инициализации вызвать метод, который загружает значения параметров из файла свойств.

Например:

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();
        } 
    }
}
person Alicia    schedule 15.09.2018

props.getProperty (имя, целое число. класс);

Это может помочь

person Siddartha    schedule 30.07.2021