2015-01-07 50 views
0

我有一个属性文件,该文件是这样的 -如何安全地读取Java中的属性文件?

[email protected] 
[email protected] 

# can be separated by comma 
whichServer=UserServer,GuestServer 

maxTestInSec=120 
numberOfUsers=1000 

现在我读的Java这样这个属性文件,如果一切都正确设置它的工作原理 -

private static final Properties prop = new Properties(); 

private static String emailFrom; 
private static String emailTo; 
private static List<String> whichServer; 
private static String maxTestInSec; 
private static String numberOfUsers; 

public static void main(String[] args) { 
    readConfig(args); 
} 

private void readConfig(String[] args) throws FileNotFoundException, IOException { 
    if (!TestUtils.isEmpty(args) && args.length != 0) { 
     prop.load(new FileInputStream(args[0])); 
    } else { 
     prop.load(TestTask.class.getClassLoader().getResourceAsStream("config.properties")); 
    } 

    emailFrom = prop.getProperty("emailFrom").trim(); 
    emailTo = prop.getProperty("emailTo").trim(); 
    whichServer = Arrays.asList(prop.getProperty("whichServer").trim().split(",")); 
    maxTestInSec = prop.getProperty("maxTestInSec").trim(); 
    numberOfUsers = prop.getProperty("numberOfUsers").trim(); 
} 

问题陈述: -

我需要确保如果任何属性值丢失,那么我想使用默认值,如果有任何机会该属性被注释掉,那么也我想使用默认值,但我会记录一条警告消息,说明属性丢失或空,所以使用默认值。我试图覆盖所有角落的情况下读取文件 -

  • 现在让我们假设,如果我不指定值来任我在上面的文件属性,然后我想用默认值属性我没有提供并记录为警告,指出没有为此属性提供值,因此使用默认值。例如:比方说,如果我没有为emailFrom字段中提供任何值,那么我想用默认值[email protected]为和他人类似的事情。所有属性的默认值是:

[email protected]

[email protected]

whichServer = UserServer的

maxTestInSec = 30

numberOfUsers = 500

  • 此外,如果任何的属性被注释掉那么上面的代码将通过NPE异常。我如何在该场景中使用默认值?

我应该开始使用命令行解析器呢?什么是处理这些东西最好和干净的方式?

我不希望有很多的if块添加一张支票,然后设置的默认值。

回答

0

在财产的情况下已被注释掉,回报将是空的,所以简单地做一个空检查。

if (prop.getProperty("name")==null) 

如果值未填满,请检查其是否等于修剪操作后的空白空间。

if (prop.getProperty("name").trim().equals("")) 
+0

感谢您的建议。有了这种方法,如果我的配置文件中有20个属性,那么这意味着我需要有40个如果块?有没有其他干净的方式来做到这一点? – john

+0

您可以使用下面的枚举来获取所有属性名称。 Enumeration en = prop.propertyNames(); (en.hasMoreElements()) { System.out.println(en.nextElement()); } 并确保您的所有属性都存在。 – robin

0

在实际使用之前,您可以尝试将该属性兑换为该地图上的静态地图和进程。

private Map<String, String> rawProps = new HashMap<String, String>; 
public static Map<String, String> actualProps = new HashMap<String, String>; 

static { 
    checkMapForNullAndReport(); 
} 

private static void checkMapForNullAndReport() { 
    // Null logic and Reporting logic 
    // Empty rawProps and populate the actualProps 
} 

这样的事情会为你工作,我相信。

1

从Java 8开始,最简单的事情就是使用getOrDefault(),它可以让你指定get站点的默认值。例如:

String email = properties.getOrDefault("emailFrom", "[email protected]"); 

这干净简洁,但意味着您需要在您访问属性的任何地方指定默认值。

如果这不会为你工作(即你会读取来自属性的值对象不止一次),你可以使用内置的支持,默认值-notice,需要一个defaultProperties对象constructor。这使您可以构建包含默认值的Properties对象,然后在加载用户的属性文件时,如果用户未指定值,它将回到默认值。

private static final Properties DEFAULTS = new Properties(); 
static { 
    DEFAULTS.setProperty("emailFrom", "[email protected]"); 
} 

public Properties getProperties() { 
    Properties props = new Properties(DEFAULTS); 
    props.load(...); 
    return props; 
} 

只需注意这不是等同于Map的构造是如何工作的 - 默认值留下作为一个独立的地图,只有.getProperty()还查询默认值;在Map中定义的方法,如.get()则没有。其中的原因有很多它是Properties一个可怕的决定延长Hashtable,但是这就是生活......


这些选项工作,但他们都容易出错,因为一)Properties是可变的和b)只有一些公开的方法回落到default实例。我宁愿不要直接暴露Properties对象,而是使用类型安全的方法创建一个包装类,以暴露我的应用程序将关心的值。这是一个更多的输入,但更安全的工作。这将是这个样子:

public class ApplicationSettings { 
    private final Properties properties = new Properties(); 
    public ApplicationSettings() { 
    properties.load(...); 
    } 

    public String emailFrom() { 
    // simple methods are concise, and encode the default right inline 
    return properties.getOrDefault("emailFrom", "[email protected]"); 
    } 

    public int getMaxTestSeconds() { 
    // You can do more complex validation if you want, too 
    String value = properties.get("maxTestInSec"); 
    if (value == null) { 
     return 30; 
    } 
    int maxTestSeconds = Integer.parseInt(value); 
    if (maxTestSeconds <= 0) { 
     // could instead log a warning and return the default if you want 
     throw new IllegalStateException(
      "maxTestInSec must be positive - was " + maxTestSeconds); 
    } 
    return maxTestSeconds; 
    } 
} 

如果你需要,你也可以将它们添加到Properties对象之前暴露setter方法是类似的验证值,虽然在默认情况下让一切只读通常是一个很好的做法。