【问题标题】:Get int, float, boolean and string from Properties从属性中获取 int、float、boolean 和 string
【发布时间】:2016-08-11 22:53:07
【问题描述】:

我有来自属性文件的 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();
    }
}

属性文件。 message.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

常量.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;
}

【问题讨论】:

  • 问题是属性文件中的一切都是字符串。除非您想使用异常并手动尝试每个解析(这很糟糕),否则我看不出如何自动解析某些内容。毕竟字符串3false 对编译器意味着什么?没什么……
  • “我不知道键和值是什么”是什么意思?你的问题不清楚
  • 好吧,再想一想,如果您只想解析布尔值、整数和双精度值,使用正则表达式(用于验证和查找类型)+反射(用于填充常量)的组合是可行的。我认为这比使用异常要好一些。
  • Dambros,这可能是使用正则表达式的一种解决方案。我确实想到了为不同的原语创建不同的属性文件,然后它将是类型安全的。
  • 您肯定需要关于属性数据类型的元数据in 属性文件。如果有人添加另一个属性IS_ENABLED = true,您的逻辑会自动将其解析为boolean,但使用该属性的代码中的实际逻辑将其视为String

标签: java constants properties-file


【解决方案1】:

这可能会有所帮助:

props.getProperty("name", Integer.class);

【讨论】:

    【解决方案2】:

    您可以在选择的类中将可配置参数定义为“静态”,并从静态初始化调用从属性文件加载参数值的方法。

    例如:

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

    【讨论】:

      【解决方案3】:

      Dambros 是对的,您存储在属性文件中的所有内容都是字符串值。 您可以在检索属性值后跟踪您的不同原始数据类型,如下所示,如 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;
          }
      }
      

      然后转换为原始 - How to convert String to primitive type value?

      我建议您通过将键值放在 String 类型 switch 语句中来跟踪您的数据类型值,然后使用键名称案例检索相关的数据类型值。 Java 7 之后可以使用字符串类型的 switch case。

      【讨论】:

      • 是的,这也是可能的解决方案。看看 Dambros 提出的想法,我们也可以为 int_message.properties 、 string_messge.properties ...等原语使用不同的文件。
      【解决方案4】:

      遵循 dropwizard 配置模式,您可以使用 YAML 而不是 Properties 来定义常量,并使用 Jackson 将其反序列化到您的类中。除了类型安全之外,dropwizard 的配置模式更进了一步,它允许 Hibernate Validator 注解来验证值是否在您的预期范围内。

      以 dropwizard 为例...

      有关所涉及技术的更多信息...

      • github.com/FasterXML/jackson-dataformat-yaml
      • hibernate.org/validator/

      【讨论】:

        【解决方案5】:

        Spring Boot 已为 type-safe configuration 属性准备好使用和功能覆盖解决方案。

        当然,仅将 Spring 用于此任务是矫枉过正的,但 Spring 有很多很酷的功能,而这个可以吸引你到右侧 ;)

        【讨论】:

          【解决方案6】:

          不完全确定我是否完全理解问题,但有可能将属性值的类型包含在 (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]);
                  }
              }
           }
          

          【讨论】:

            【解决方案7】:

            如果您有一个配置值类,例如 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");
            

            您可以扩展代码以处理更多类型。您还可以将其更改为忽略缺少的属性,而不是像现在这样失败,这样字段声明中的分配将保持不变,即成为默认值。

            【讨论】:

            • 很好的解决方案。但是当我在常量中添加 final 时它不起作用。当我使用两个参数字段 field.getModifiers() 和 ~Modifier.FINAL 设置 Accessible true 和 setInt 时,它工作正常。
            • @PratiyushKumarSingh 您在问题中从未提到常量可以是最终的,恕我直言,这显然是您迄今为止的最佳选择
            • @PratiyushKumarSingh 但如果您不想让他们成为public,请标记他们private 并使用public static getXXX() 方法。
            【解决方案8】:

            如果知道常量的类型,可以使用Apache Commons Collections

            例如,您可以根据常量的类型使用一些实用程序方法。

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

            您甚至可以使用默认值来避免错误。

            【讨论】:

            • 是的,如果我们知道原始数据类型,它就可以正常工作。但是我们不能为 100 个这样的属性值硬编码或编写代码。
            • @PratiyushKumarSingh 为什么不能硬编码数据类型,而必须硬编码类型?例如。 SSO_URL定义String(硬编码),所以调用getString()(匹配硬编码)。
            • 是的,Andreas,目前我正在这样做,但它看起来不像优化的解决方案。
            猜你喜欢
            • 2015-02-13
            • 2020-02-12
            • 1970-01-01
            • 2018-05-17
            • 2023-03-04
            • 2022-10-04
            • 2013-10-31
            • 2021-10-08
            • 1970-01-01
            相关资源
            最近更新 更多