001/** 002 * Copyright (C) 2011-2012 Typesafe Inc. <http://typesafe.com> 003 */ 004package com.typesafe.config; 005 006 007/** 008 * A set of options related to parsing. 009 * 010 * <p> 011 * This object is immutable, so the "setters" return a new object. 012 * 013 * <p> 014 * Here is an example of creating a custom {@code ConfigParseOptions}: 015 * 016 * <pre> 017 * ConfigParseOptions options = ConfigParseOptions.defaults() 018 * .setSyntax(ConfigSyntax.JSON) 019 * .setAllowMissing(false) 020 * </pre> 021 * 022 */ 023public final class ConfigParseOptions { 024 final ConfigSyntax syntax; 025 final String originDescription; 026 final boolean allowMissing; 027 final ConfigIncluder includer; 028 final ClassLoader classLoader; 029 030 private ConfigParseOptions(ConfigSyntax syntax, String originDescription, boolean allowMissing, 031 ConfigIncluder includer, ClassLoader classLoader) { 032 this.syntax = syntax; 033 this.originDescription = originDescription; 034 this.allowMissing = allowMissing; 035 this.includer = includer; 036 this.classLoader = classLoader; 037 } 038 039 /** 040 * Gets an instance of <code>ConfigParseOptions</code> with all fields 041 * set to the default values. Start with this instance and make any 042 * changes you need. 043 * @return the default parse options 044 */ 045 public static ConfigParseOptions defaults() { 046 return new ConfigParseOptions(null, null, true, null, null); 047 } 048 049 /** 050 * Set the file format. If set to null, try to guess from any available 051 * filename extension; if guessing fails, assume {@link ConfigSyntax#CONF}. 052 * 053 * @param syntax 054 * a syntax or {@code null} for best guess 055 * @return options with the syntax set 056 */ 057 public ConfigParseOptions setSyntax(ConfigSyntax syntax) { 058 if (this.syntax == syntax) 059 return this; 060 else 061 return new ConfigParseOptions(syntax, this.originDescription, this.allowMissing, 062 this.includer, this.classLoader); 063 } 064 065 /** 066 * Gets the current syntax option, which may be null for "any". 067 * @return the current syntax or null 068 */ 069 public ConfigSyntax getSyntax() { 070 return syntax; 071 } 072 073 /** 074 * Set a description for the thing being parsed. In most cases this will be 075 * set up for you to something like the filename, but if you provide just an 076 * input stream you might want to improve on it. Set to null to allow the 077 * library to come up with something automatically. This description is the 078 * basis for the {@link ConfigOrigin} of the parsed values. 079 * 080 * @param originDescription description to put in the {@link ConfigOrigin} 081 * @return options with the origin description set 082 */ 083 public ConfigParseOptions setOriginDescription(String originDescription) { 084 // findbugs complains about == here but is wrong, do not "fix" 085 if (this.originDescription == originDescription) 086 return this; 087 else if (this.originDescription != null && originDescription != null 088 && this.originDescription.equals(originDescription)) 089 return this; 090 else 091 return new ConfigParseOptions(this.syntax, originDescription, this.allowMissing, 092 this.includer, this.classLoader); 093 } 094 095 /** 096 * Gets the current origin description, which may be null for "automatic". 097 * @return the current origin description or null 098 */ 099 public String getOriginDescription() { 100 return originDescription; 101 } 102 103 /** this is package-private, not public API */ 104 ConfigParseOptions withFallbackOriginDescription(String originDescription) { 105 if (this.originDescription == null) 106 return setOriginDescription(originDescription); 107 else 108 return this; 109 } 110 111 /** 112 * Set to false to throw an exception if the item being parsed (for example 113 * a file) is missing. Set to true to just return an empty document in that 114 * case. Note that this setting applies on only to fetching the root document, 115 * it has no effect on any nested includes. 116 * 117 * @param allowMissing true to silently ignore missing item 118 * @return options with the "allow missing" flag set 119 */ 120 public ConfigParseOptions setAllowMissing(boolean allowMissing) { 121 if (this.allowMissing == allowMissing) 122 return this; 123 else 124 return new ConfigParseOptions(this.syntax, this.originDescription, allowMissing, 125 this.includer, this.classLoader); 126 } 127 128 /** 129 * Gets the current "allow missing" flag. 130 * @return whether we allow missing files 131 */ 132 public boolean getAllowMissing() { 133 return allowMissing; 134 } 135 136 /** 137 * Set a {@link ConfigIncluder} which customizes how includes are handled. 138 * null means to use the default includer. 139 * 140 * @param includer the includer to use or null for default 141 * @return new version of the parse options with different includer 142 */ 143 public ConfigParseOptions setIncluder(ConfigIncluder includer) { 144 if (this.includer == includer) 145 return this; 146 else 147 return new ConfigParseOptions(this.syntax, this.originDescription, this.allowMissing, 148 includer, this.classLoader); 149 } 150 151 /** 152 * Prepends a {@link ConfigIncluder} which customizes how 153 * includes are handled. To prepend your includer, the 154 * library calls {@link ConfigIncluder#withFallback} on your 155 * includer to append the existing includer to it. 156 * 157 * @param includer the includer to prepend (may not be null) 158 * @return new version of the parse options with different includer 159 */ 160 public ConfigParseOptions prependIncluder(ConfigIncluder includer) { 161 if (includer == null) 162 throw new NullPointerException("null includer passed to prependIncluder"); 163 if (this.includer == includer) 164 return this; 165 else if (this.includer != null) 166 return setIncluder(includer.withFallback(this.includer)); 167 else 168 return setIncluder(includer); 169 } 170 171 /** 172 * Appends a {@link ConfigIncluder} which customizes how 173 * includes are handled. To append, the library calls {@link 174 * ConfigIncluder#withFallback} on the existing includer. 175 * 176 * @param includer the includer to append (may not be null) 177 * @return new version of the parse options with different includer 178 */ 179 public ConfigParseOptions appendIncluder(ConfigIncluder includer) { 180 if (includer == null) 181 throw new NullPointerException("null includer passed to appendIncluder"); 182 if (this.includer == includer) 183 return this; 184 else if (this.includer != null) 185 return setIncluder(this.includer.withFallback(includer)); 186 else 187 return setIncluder(includer); 188 } 189 190 /** 191 * Gets the current includer (will be null for the default includer). 192 * @return current includer or null 193 */ 194 public ConfigIncluder getIncluder() { 195 return includer; 196 } 197 198 /** 199 * Set the class loader. If set to null, 200 * <code>Thread.currentThread().getContextClassLoader()</code> will be used. 201 * 202 * @param loader 203 * a class loader or {@code null} to use thread context class 204 * loader 205 * @return options with the class loader set 206 */ 207 public ConfigParseOptions setClassLoader(ClassLoader loader) { 208 if (this.classLoader == loader) 209 return this; 210 else 211 return new ConfigParseOptions(this.syntax, this.originDescription, this.allowMissing, 212 this.includer, loader); 213 } 214 215 /** 216 * Get the class loader; never returns {@code null}, if the class loader was 217 * unset, returns 218 * <code>Thread.currentThread().getContextClassLoader()</code>. 219 * 220 * @return class loader to use 221 */ 222 public ClassLoader getClassLoader() { 223 if (this.classLoader == null) 224 return Thread.currentThread().getContextClassLoader(); 225 else 226 return this.classLoader; 227 } 228}