iter = this.paths.iterator(); iter.hasNext();) {
String path = iter.next();
if (path.equals(".") || path.equals("")) {
+ // Empty path is always on the classpath so no need for it to be
+ // explicitly listed here
iter.remove();
}
}
@@ -278,12 +286,11 @@ public class PropertiesLauncher extends Launcher {
@Override
protected String getMainClass(Archive archive) throws Exception {
if (System.getProperty(MAIN) != null) {
- return SystemPropertyUtils
- .resolvePlaceholders(System.getProperty(MAIN), true);
+ return SystemPropertyUtils.resolvePlaceholders(System.getProperty(MAIN));
}
if (this.properties.containsKey(MAIN)) {
- return SystemPropertyUtils.resolvePlaceholders(
- this.properties.getProperty(MAIN), true);
+ return SystemPropertyUtils.resolvePlaceholders(this.properties
+ .getProperty(MAIN));
}
return super.getMainClass(archive);
}
diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/util/PropertyPlaceholderHelper.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/util/PropertyPlaceholderHelper.java
deleted file mode 100644
index 61634d295b..0000000000
--- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/util/PropertyPlaceholderHelper.java
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * Copyright 2012-2013 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.boot.loader.util;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-
-/**
- * Utility class for working with Strings that have placeholder values in them. A
- * placeholder takes the form {@code $ name} . Using {@code PropertyPlaceholderHelper}
- * these placeholders can be substituted for user-supplied values.
- *
- * Values for substitution can be supplied using a {@link Properties} instance or using a
- * {@link PlaceholderResolver}.
- *
- * @author Juergen Hoeller
- * @author Rob Harrop
- * @since 3.0
- */
-public class PropertyPlaceholderHelper {
-
- private static final Map wellKnownSimplePrefixes = new HashMap(
- 4);
-
- static {
- wellKnownSimplePrefixes.put("}", "{");
- wellKnownSimplePrefixes.put("]", "[");
- wellKnownSimplePrefixes.put(")", "(");
- }
-
- private final String placeholderPrefix;
-
- private final String placeholderSuffix;
-
- private final String simplePrefix;
-
- private final String valueSeparator;
-
- private final boolean ignoreUnresolvablePlaceholders;
-
- /**
- * Creates a new {@code PropertyPlaceholderHelper} that uses the supplied prefix and
- * suffix. Unresolvable placeholders are ignored.
- * @param placeholderPrefix the prefix that denotes the start of a placeholder.
- * @param placeholderSuffix the suffix that denotes the end of a placeholder.
- */
- public PropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix) {
- this(placeholderPrefix, placeholderSuffix, null, true);
- }
-
- /**
- * Creates a new {@code PropertyPlaceholderHelper} that uses the supplied prefix and
- * suffix.
- * @param placeholderPrefix the prefix that denotes the start of a placeholder
- * @param placeholderSuffix the suffix that denotes the end of a placeholder
- * @param valueSeparator the separating character between the placeholder variable and
- * the associated default value, if any
- * @param ignoreUnresolvablePlaceholders indicates whether unresolvable placeholders
- * should be ignored ({@code true}) or cause an exception ({@code false}).
- */
- public PropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix,
- String valueSeparator, boolean ignoreUnresolvablePlaceholders) {
-
- Assert.notNull(placeholderPrefix, "placeholderPrefix must not be null");
- Assert.notNull(placeholderSuffix, "placeholderSuffix must not be null");
- this.placeholderPrefix = placeholderPrefix;
- this.placeholderSuffix = placeholderSuffix;
- String simplePrefixForSuffix = wellKnownSimplePrefixes
- .get(this.placeholderSuffix);
- if (simplePrefixForSuffix != null
- && this.placeholderPrefix.endsWith(simplePrefixForSuffix)) {
- this.simplePrefix = simplePrefixForSuffix;
- }
- else {
- this.simplePrefix = this.placeholderPrefix;
- }
- this.valueSeparator = valueSeparator;
- this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders;
- }
-
- /**
- * Replaces all placeholders of format ${name}
with the corresponding
- * property from the supplied {@link Properties}.
- * @param value the value containing the placeholders to be replaced.
- * @param properties the {@code Properties} to use for replacement.
- * @return the supplied value with placeholders replaced inline.
- */
- public String replacePlaceholders(String value, final Properties properties) {
- Assert.notNull(properties, "Argument 'properties' must not be null.");
- return replacePlaceholders(value, new PlaceholderResolver() {
- @Override
- public String resolvePlaceholder(String placeholderName) {
- return properties.getProperty(placeholderName);
- }
- });
- }
-
- /**
- * Replaces all placeholders of format {@code $ name} with the value returned from the
- * supplied {@link PlaceholderResolver}.
- * @param value the value containing the placeholders to be replaced.
- * @param placeholderResolver the {@code PlaceholderResolver} to use for replacement.
- * @return the supplied value with placeholders replaced inline.
- */
- public String replacePlaceholders(String value,
- PlaceholderResolver placeholderResolver) {
- Assert.notNull(value, "Argument 'value' must not be null.");
- return parseStringValue(value, placeholderResolver, new HashSet());
- }
-
- protected String parseStringValue(String strVal,
- PlaceholderResolver placeholderResolver, Set visitedPlaceholders) {
-
- StringBuilder buf = new StringBuilder(strVal);
-
- int startIndex = strVal.indexOf(this.placeholderPrefix);
- while (startIndex != -1) {
- int endIndex = findPlaceholderEndIndex(buf, startIndex);
- if (endIndex != -1) {
- String placeholder = buf.substring(
- startIndex + this.placeholderPrefix.length(), endIndex);
- String originalPlaceholder = placeholder;
- if (!visitedPlaceholders.add(originalPlaceholder)) {
- throw new IllegalArgumentException("Circular placeholder reference '"
- + originalPlaceholder + "' in property definitions");
- }
- // Recursive invocation, parsing placeholders contained in the placeholder
- // key.
- placeholder = parseStringValue(placeholder, placeholderResolver,
- visitedPlaceholders);
- // Now obtain the value for the fully resolved key...
- String propVal = placeholderResolver.resolvePlaceholder(placeholder);
- if (propVal == null && this.valueSeparator != null) {
- int separatorIndex = placeholder.indexOf(this.valueSeparator);
- if (separatorIndex != -1) {
- String actualPlaceholder = placeholder.substring(0,
- separatorIndex);
- String defaultValue = placeholder.substring(separatorIndex
- + this.valueSeparator.length());
- propVal = placeholderResolver
- .resolvePlaceholder(actualPlaceholder);
- if (propVal == null) {
- propVal = defaultValue;
- }
- }
- }
- if (propVal != null) {
- // Recursive invocation, parsing placeholders contained in the
- // previously resolved placeholder value.
- propVal = parseStringValue(propVal, placeholderResolver,
- visitedPlaceholders);
- buf.replace(startIndex, endIndex + this.placeholderSuffix.length(),
- propVal);
- startIndex = buf.indexOf(this.placeholderPrefix,
- startIndex + propVal.length());
- }
- else if (this.ignoreUnresolvablePlaceholders) {
- // Proceed with unprocessed value.
- startIndex = buf.indexOf(this.placeholderPrefix, endIndex
- + this.placeholderSuffix.length());
- }
- else {
- throw new IllegalArgumentException("Could not resolve placeholder '"
- + placeholder + "'" + " in string value \"" + strVal + "\"");
- }
- visitedPlaceholders.remove(originalPlaceholder);
- }
- else {
- startIndex = -1;
- }
- }
-
- return buf.toString();
- }
-
- private int findPlaceholderEndIndex(CharSequence buf, int startIndex) {
- int index = startIndex + this.placeholderPrefix.length();
- int withinNestedPlaceholder = 0;
- while (index < buf.length()) {
- if (substringMatch(buf, index, this.placeholderSuffix)) {
- if (withinNestedPlaceholder > 0) {
- withinNestedPlaceholder--;
- index = index + this.placeholderSuffix.length();
- }
- else {
- return index;
- }
- }
- else if (substringMatch(buf, index, this.simplePrefix)) {
- withinNestedPlaceholder++;
- index = index + this.simplePrefix.length();
- }
- else {
- index++;
- }
- }
- return -1;
- }
-
- /**
- * Strategy interface used to resolve replacement values for placeholders contained in
- * Strings.
- * @see PropertyPlaceholderHelper
- */
- public static interface PlaceholderResolver {
-
- /**
- * Resolves the supplied placeholder name into the replacement value.
- * @param placeholderName the name of the placeholder to resolve
- * @return the replacement value or {@code null} if no replacement is to be made
- */
- String resolvePlaceholder(String placeholderName);
- }
-
- public static boolean substringMatch(CharSequence str, int index,
- CharSequence substring) {
- for (int j = 0; j < substring.length(); j++) {
- int i = index + j;
- if (i >= str.length() || str.charAt(i) != substring.charAt(j)) {
- return false;
- }
- }
- return true;
- }
-
- public static class Assert {
-
- public static void notNull(Object target, String message) {
- if (target == null) {
- throw new IllegalStateException(message);
- }
- }
-
- }
-
-}
\ No newline at end of file
diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/util/SystemPropertyUtils.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/util/SystemPropertyUtils.java
index c69a985fc6..9b8a58378a 100644
--- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/util/SystemPropertyUtils.java
+++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/util/SystemPropertyUtils.java
@@ -16,22 +16,27 @@
package org.springframework.boot.loader.util;
-import org.springframework.boot.loader.util.PropertyPlaceholderHelper.PlaceholderResolver;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver;
/**
* Helper class for resolving placeholders in texts. Usually applied to file paths.
*
*
- * A text may contain {@code $ ...}} placeholders, to be resolved as system properties:
- * e.g. {@code $ user.dir}}. Default values can be supplied using the ":" separator
+ * A text may contain {@code $ ...} placeholders, to be resolved as system properties:
+ * e.g. {@code $ user.dir} . Default values can be supplied using the ":" separator
* between key and value.
*
+ *
+ *
+ * Adapted from Spring.
+ *
* @author Juergen Hoeller
* @author Rob Harrop
* @author Dave Syer
- * @since 1.2.5
- * @see #PLACEHOLDER_PREFIX
- * @see #PLACEHOLDER_SUFFIX
+ *
* @see System#getProperty(String)
*/
public abstract class SystemPropertyUtils {
@@ -45,11 +50,7 @@ public abstract class SystemPropertyUtils {
/** Value separator for system property placeholders: ":" */
public static final String VALUE_SEPARATOR = ":";
- private static final PropertyPlaceholderHelper strictHelper = new PropertyPlaceholderHelper(
- PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, VALUE_SEPARATOR, false);
-
- private static final PropertyPlaceholderHelper nonStrictHelper = new PropertyPlaceholderHelper(
- PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, VALUE_SEPARATOR, true);
+ private static final PropertyPlaceholderHelper helper = new PropertyPlaceholderHelper();
/**
* Resolve ${...} placeholders in the given text, replacing them with corresponding
@@ -61,40 +62,86 @@ public abstract class SystemPropertyUtils {
* @throws IllegalArgumentException if there is an unresolvable placeholder
*/
public static String resolvePlaceholders(String text) {
- return resolvePlaceholders(text, false);
+ return helper.replacePlaceholders(text);
}
- /**
- * Resolve ${...} placeholders in the given text, replacing them with corresponding
- * system property values. Unresolvable placeholders with no default value are ignored
- * and passed through unchanged if the flag is set to true.
- * @param text the String to resolve
- * @param ignoreUnresolvablePlaceholders flag to determine is unresolved placeholders
- * are ignored
- * @return the resolved String
- * @see #PLACEHOLDER_PREFIX
- * @see #PLACEHOLDER_SUFFIX
- * @throws IllegalArgumentException if there is an unresolvable placeholder and the
- * flag is false
- */
- public static String resolvePlaceholders(String text,
- boolean ignoreUnresolvablePlaceholders) {
- PropertyPlaceholderHelper helper = (ignoreUnresolvablePlaceholders ? nonStrictHelper
- : strictHelper);
- return helper.replacePlaceholders(text, new SystemPropertyPlaceholderResolver(
- text));
- }
+ static protected class PropertyPlaceholderHelper {
- private static class SystemPropertyPlaceholderResolver implements PlaceholderResolver {
+ private static final String simplePrefix = PLACEHOLDER_PREFIX.substring(1);
- private final String text;
+ /**
+ * Replaces all placeholders of format {@code $ name} with the value returned from
+ * the supplied {@link PlaceholderResolver}.
+ * @param value the value containing the placeholders to be replaced.
+ * @return the supplied value with placeholders replaced inline.
+ */
+ public String replacePlaceholders(String value) {
+ Assert.notNull(value, "Argument 'value' must not be null.");
+ return parseStringValue(value, value, new HashSet());
+ }
+
+ private String parseStringValue(String value, String current,
+ Set visitedPlaceholders) {
+
+ StringBuilder buf = new StringBuilder(current);
+
+ int startIndex = current.indexOf(PLACEHOLDER_PREFIX);
+ while (startIndex != -1) {
+ int endIndex = findPlaceholderEndIndex(buf, startIndex);
+ if (endIndex != -1) {
+ String placeholder = buf.substring(
+ startIndex + PLACEHOLDER_PREFIX.length(), endIndex);
+ String originalPlaceholder = placeholder;
+ if (!visitedPlaceholders.add(originalPlaceholder)) {
+ throw new IllegalArgumentException(
+ "Circular placeholder reference '" + originalPlaceholder
+ + "' in property definitions");
+ }
+ // Recursive invocation, parsing placeholders contained in the
+ // placeholder
+ // key.
+ placeholder = parseStringValue(value, placeholder,
+ visitedPlaceholders);
+ // Now obtain the value for the fully resolved key...
+ String propVal = resolvePlaceholder(value, placeholder);
+ if (propVal == null && VALUE_SEPARATOR != null) {
+ int separatorIndex = placeholder.indexOf(VALUE_SEPARATOR);
+ if (separatorIndex != -1) {
+ String actualPlaceholder = placeholder.substring(0,
+ separatorIndex);
+ String defaultValue = placeholder.substring(separatorIndex
+ + VALUE_SEPARATOR.length());
+ propVal = resolvePlaceholder(value, actualPlaceholder);
+ if (propVal == null) {
+ propVal = defaultValue;
+ }
+ }
+ }
+ if (propVal != null) {
+ // Recursive invocation, parsing placeholders contained in the
+ // previously resolved placeholder value.
+ propVal = parseStringValue(value, propVal, visitedPlaceholders);
+ buf.replace(startIndex, endIndex + PLACEHOLDER_SUFFIX.length(),
+ propVal);
+ startIndex = buf.indexOf(PLACEHOLDER_PREFIX,
+ startIndex + propVal.length());
+ }
+ else {
+ // Proceed with unprocessed value.
+ startIndex = buf.indexOf(PLACEHOLDER_PREFIX, endIndex
+ + PLACEHOLDER_SUFFIX.length());
+ }
+ visitedPlaceholders.remove(originalPlaceholder);
+ }
+ else {
+ startIndex = -1;
+ }
+ }
- public SystemPropertyPlaceholderResolver(String text) {
- this.text = text;
+ return buf.toString();
}
- @Override
- public String resolvePlaceholder(String placeholderName) {
+ private String resolvePlaceholder(String text, String placeholderName) {
try {
String propVal = System.getProperty(placeholderName);
if (propVal == null) {
@@ -105,10 +152,57 @@ public abstract class SystemPropertyUtils {
}
catch (Throwable ex) {
System.err.println("Could not resolve placeholder '" + placeholderName
- + "' in [" + this.text + "] as system property: " + ex);
+ + "' in [" + text + "] as system property: " + ex);
return null;
}
}
+
+ private int findPlaceholderEndIndex(CharSequence buf, int startIndex) {
+ int index = startIndex + PLACEHOLDER_PREFIX.length();
+ int withinNestedPlaceholder = 0;
+ while (index < buf.length()) {
+ if (substringMatch(buf, index, PLACEHOLDER_SUFFIX)) {
+ if (withinNestedPlaceholder > 0) {
+ withinNestedPlaceholder--;
+ index = index + PLACEHOLDER_SUFFIX.length();
+ }
+ else {
+ return index;
+ }
+ }
+ else if (substringMatch(buf, index,
+ PropertyPlaceholderHelper.simplePrefix)) {
+ withinNestedPlaceholder++;
+ index = index + PropertyPlaceholderHelper.simplePrefix.length();
+ }
+ else {
+ index++;
+ }
+ }
+ return -1;
+ }
+
+ private static boolean substringMatch(CharSequence str, int index,
+ CharSequence substring) {
+ for (int j = 0; j < substring.length(); j++) {
+ int i = index + j;
+ if (i >= str.length() || str.charAt(i) != substring.charAt(j)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static class Assert {
+
+ public static void notNull(Object target, String message) {
+ if (target == null) {
+ throw new IllegalStateException(message);
+ }
+ }
+
+ }
+
}
}
diff --git a/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/PropertiesLauncherTests.java b/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/PropertiesLauncherTests.java
new file mode 100644
index 0000000000..aae8fee959
--- /dev/null
+++ b/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/PropertiesLauncherTests.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2012-2013 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.loader;
+
+import org.junit.After;
+import org.junit.Test;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author Dave Syer
+ */
+public class PropertiesLauncherTests {
+
+ private PropertiesLauncher launcher = new PropertiesLauncher();
+
+ @After
+ public void close() {
+ System.clearProperty("loader.home");
+ System.clearProperty("loader.path");
+ System.clearProperty("loader.main");
+ System.clearProperty("loader.config.name");
+ System.clearProperty("loader.config.location");
+ }
+
+ @Test
+ public void testDefaultHome() {
+ assertEquals(System.getProperty("user.dir"), this.launcher.getHomeDirectory());
+ }
+
+ @Test
+ public void testUserSpecifiedMain() throws Exception {
+ this.launcher.initialize();
+ assertEquals("demo.Application", this.launcher.getMainClass(null));
+ }
+
+ @Test
+ public void testUserSpecifiedConfigName() throws Exception {
+ System.setProperty("loader.config.name", "foo");
+ this.launcher.initialize();
+ assertEquals("my.Application", this.launcher.getMainClass(null));
+ assertEquals("[etc/]", ReflectionTestUtils.getField(this.launcher, "paths")
+ .toString());
+ }
+
+ @Test
+ public void testSystemPropertySpecifiedMain() throws Exception {
+ System.setProperty("loader.main", "foo.Bar");
+ this.launcher.initialize();
+ assertEquals("foo.Bar", this.launcher.getMainClass(null));
+ }
+
+}
diff --git a/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/util/SystemPropertyUtilsTests.java b/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/util/SystemPropertyUtilsTests.java
new file mode 100644
index 0000000000..ce57cb4808
--- /dev/null
+++ b/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/util/SystemPropertyUtilsTests.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2012-2013 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.loader.util;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.springframework.boot.loader.util.SystemPropertyUtils;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author Dave Syer
+ */
+public class SystemPropertyUtilsTests {
+
+ @BeforeClass
+ public static void init() {
+ System.setProperty("foo", "bar");
+ }
+
+ @AfterClass
+ public static void close() {
+ System.clearProperty("foo");
+ }
+
+ @Test
+ public void testVanillaPlaceholder() {
+ assertEquals("bar", SystemPropertyUtils.resolvePlaceholders("${foo}"));
+ }
+
+ @Test
+ public void testDefaultValue() {
+ assertEquals("foo", SystemPropertyUtils.resolvePlaceholders("${bar:foo}"));
+ }
+
+ @Test
+ public void testNestedPlaceholder() {
+ assertEquals("foo", SystemPropertyUtils.resolvePlaceholders("${bar:${spam:foo}}"));
+ }
+
+}
diff --git a/spring-boot-tools/spring-boot-loader/src/test/resources/application.properties b/spring-boot-tools/spring-boot-loader/src/test/resources/application.properties
new file mode 100644
index 0000000000..36edcf1c96
--- /dev/null
+++ b/spring-boot-tools/spring-boot-loader/src/test/resources/application.properties
@@ -0,0 +1,2 @@
+loader.main: demo.Application
+loader.path: etc/,lib,.
\ No newline at end of file
diff --git a/spring-boot-tools/spring-boot-loader/src/test/resources/foo.properties b/spring-boot-tools/spring-boot-loader/src/test/resources/foo.properties
new file mode 100644
index 0000000000..495dc6b44d
--- /dev/null
+++ b/spring-boot-tools/spring-boot-loader/src/test/resources/foo.properties
@@ -0,0 +1,2 @@
+loader.main: my.Application
+loader.path: etc
\ No newline at end of file