You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2021/12/26 19:43:49 UTC
[juneau] branch master updated: Config API modernization.
This is an automated email from the ASF dual-hosted git repository.
jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git
The following commit(s) were added to refs/heads/master by this push:
new 94239f1 Config API modernization.
94239f1 is described below
commit 94239f137ba059d64cb8e72f0500905c4a8b3973
Author: JamesBognar <ja...@salesforce.com>
AuthorDate: Sun Dec 26 14:43:30 2021 -0500
Config API modernization.
---
.../main/java/org/apache/juneau/config/Config.java | 214 +------------
.../java/org/apache/juneau/config/Section.java | 353 +++++++++++++++++++++
.../microservice/resources/ConfigResource.java | 28 +-
.../org/apache/juneau/rest/test/ConfigTest.java | 2 +-
.../apache/juneau/config/ConfigInterfaceTest.java | 2 +-
.../java/org/apache/juneau/config/ConfigTest.java | 65 ++--
6 files changed, 409 insertions(+), 255 deletions(-)
diff --git a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java
index 33ce5f4..af9175e 100644
--- a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java
+++ b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java
@@ -19,7 +19,6 @@ import static org.apache.juneau.internal.SystemEnv.*;
import static org.apache.juneau.internal.ThrowableUtils.*;
import static org.apache.juneau.internal.IOUtils.*;
-import java.beans.*;
import java.io.*;
import java.lang.annotation.*;
import java.lang.reflect.*;
@@ -671,7 +670,7 @@ public final class Config extends Context implements ConfigEventListener {
* @return This object.
*/
public Config setSystemProperties() {
- for (String section : getSections()) {
+ for (String section : getSectionNames()) {
for (String key : getKeys(section)) {
String k = (section.isEmpty() ? key : section + '/' + key);
System.setProperty(k, getRaw(k));
@@ -877,13 +876,26 @@ public final class Config extends Context implements ConfigEventListener {
* If entry does not exist, returns an empty {@link Entry} object.
*
* @param key The key.
- * @return The value, never <jk>null</jk>.
+ * @return The entry bean, never <jk>null</jk>.
*/
public Entry get(String key) {
return new Entry(this, configMap, sname(key), skey(key));
}
/**
+ * Gets the section with the specified name.
+ *
+ * <p>
+ * If section does not exist, returns an empty {@link Section} object.
+ *
+ * @param name The section name. <jk>null</jk> and blank refer to the default section.
+ * @return The section bean, never <jk>null</jk>.
+ */
+ public Section getSection(String name) {
+ return new Section(this, configMap, emptyIfNull(name));
+ }
+
+ /**
* Returns the keys of the entries in the specified section.
*
* @param section
@@ -936,209 +948,15 @@ public final class Config extends Context implements ConfigEventListener {
}
/**
- * Shortcut for calling <code>getSectionAsBean(sectionName, c, <jk>false</jk>)</code>.
- *
- * @param section
- * The section name to write from.
- * <br>If empty, refers to the default section.
- * <br>Must not be <jk>null</jk>.
- * @param c The bean class to create.
- * @return A new bean instance.
- * @throws ParseException Malformed input encountered.
- */
- public <T> T getSectionAsBean(String section, Class<T> c) throws ParseException {
- return getSectionAsBean(section, c, false);
- }
-
- /**
- * Converts this config file section to the specified bean instance.
- *
- * <p>
- * Key/value pairs in the config file section get copied as bean property values to the specified bean class.
- *
- * <h5 class='figure'>Example config file</h5>
- * <p class='bcode w800'>
- * <cs>[MyAddress]</cs>
- * <ck>name</ck> = <cv>John Smith</cv>
- * <ck>street</ck> = <cv>123 Main Street</cv>
- * <ck>city</ck> = <cv>Anywhere</cv>
- * <ck>state</ck> = <cv>NY</cv>
- * <ck>zip</ck> = <cv>12345</cv>
- * </p>
- *
- * <h5 class='figure'>Example bean</h5>
- * <p class='bcode w800'>
- * <jk>public class</jk> Address {
- * public String name, street, city;
- * public StateEnum state;
- * public int zip;
- * }
- * </p>
- *
- * <h5 class='figure'>Example usage</h5>
- * <p class='bcode w800'>
- * Config cf = Config.<jsm>create</jsm>().name(<js>"MyConfig.cfg"</js>).build();
- * Address myAddress = cf.getSectionAsBean(<js>"MySection"</js>, Address.<jk>class</jk>);
- * </p>
- *
- * @param section
- * The section name to write from.
- * <br>If empty, refers to the default section.
- * <br>Must not be <jk>null</jk>.
- * @param c The bean class to create.
- * @param ignoreUnknownProperties
- * If <jk>false</jk>, throws a {@link ParseException} if the section contains an entry that isn't a bean property
- * name.
- * @return A new bean instance, or <jk>null</jk> if the section doesn't exist.
- * @throws ParseException Unknown property was encountered in section.
- */
- public <T> T getSectionAsBean(String section, Class<T> c, boolean ignoreUnknownProperties) throws ParseException {
- assertArgNotNull("c", c);
- section = section(section);
-
- if (! configMap.hasSection(section))
- return null;
-
- Set<String> keys = configMap.getKeys(section);
-
- BeanMap<T> bm = beanSession.newBeanMap(c);
- for (String k : keys) {
- BeanPropertyMeta bpm = bm.getPropertyMeta(k);
- if (bpm == null) {
- if (! ignoreUnknownProperties)
- throw new ParseException("Unknown property ''{0}'' encountered in configuration section ''{1}''.", k, section);
- } else {
- bm.put(k, get(section + '/' + k).as(bpm.getClassMeta().getInnerClass()).orElse(null));
- }
- }
-
- return bm.getBean();
- }
-
- /**
- * Returns a section of this config copied into an {@link OMap}.
- *
- * @param section
- * The section name to write from.
- * <br>If empty, refers to the default section.
- * <br>Must not be <jk>null</jk>.
- * @return A new {@link OMap}, or <jk>null</jk> if the section doesn't exist.
- * @throws ParseException Malformed input encountered.
- */
- public OMap getSectionAsMap(String section) throws ParseException {
- section = section(section);
-
- if (! configMap.hasSection(section))
- return null;
-
- Set<String> keys = configMap.getKeys(section);
-
- OMap om = new OMap();
- for (String k : keys)
- om.put(k, get(section + '/' + k).as(Object.class).orElse(null));
- return om;
- }
-
- /**
* Returns the section names defined in this config.
*
* @return The section names defined in this config.
*/
- public Set<String> getSections() {
+ public Set<String> getSectionNames() {
return Collections.unmodifiableSet(configMap.getSections());
}
/**
- * Wraps a config file section inside a Java interface so that values in the section can be read and
- * write using getters and setters.
- *
- * <h5 class='figure'>Example config file</h5>
- * <p class='bcode w800'>
- * <cs>[MySection]</cs>
- * <ck>string</ck> = <cv>foo</cv>
- * <ck>int</ck> = <cv>123</cv>
- * <ck>enum</ck> = <cv>ONE</cv>
- * <ck>bean</ck> = <cv>{foo:'bar',baz:123}</cv>
- * <ck>int3dArray</ck> = <cv>[[[123,null],null],null]</cv>
- * <ck>bean1d3dListMap</ck> = <cv>{key:[[[[{foo:'bar',baz:123}]]]]}</cv>
- * </p>
- *
- * <h5 class='figure'>Example interface</h5>
- * <p class='bcode w800'>
- * <jk>public interface</jk> MyConfigInterface {
- *
- * String getString();
- * <jk>void</jk> setString(String x);
- *
- * <jk>int</jk> getInt();
- * <jk>void</jk> setInt(<jk>int</jk> x);
- *
- * MyEnum getEnum();
- * <jk>void</jk> setEnum(MyEnum x);
- *
- * MyBean getBean();
- * <jk>void</jk> setBean(MyBean x);
- *
- * <jk>int</jk>[][][] getInt3dArray();
- * <jk>void</jk> setInt3dArray(<jk>int</jk>[][][] x);
- *
- * Map<String,List<MyBean[][][]>> getBean1d3dListMap();
- * <jk>void</jk> setBean1d3dListMap(Map<String,List<MyBean[][][]>> x);
- * }
- * </p>
- *
- * <h5 class='figure'>Example usage</h5>
- * <p class='bcode w800'>
- * Config cf = Config.<jsm>create</jsm>().name(<js>"MyConfig.cfg"</js>).build();
- *
- * MyConfigInterface ci = cf.getSectionAsInterface(<js>"MySection"</js>, MyConfigInterface.<jk>class</jk>);
- *
- * <jk>int</jk> myInt = ci.getInt();
- *
- * ci.setBean(<jk>new</jk> MyBean());
- *
- * cf.save();
- * </p>
- *
- * <ul class='notes'>
- * <li>Calls to setters when the configuration is read-only will cause {@link UnsupportedOperationException} to be thrown.
- * </ul>
- *
- * @param section
- * The section name to write from.
- * <br>If empty, refers to the default section.
- * <br>Must not be <jk>null</jk>.
- * @param c The proxy interface class.
- * @return The proxy interface.
- */
- @SuppressWarnings("unchecked")
- public <T> T getSectionAsInterface(String section, final Class<T> c) {
- assertArgNotNull("c", c);
- final String section2 = section(section);
-
- if (! c.isInterface())
- throw illegalArgumentException("Class ''{0}'' passed to getSectionAsInterface() is not an interface.", c.getName());
-
- InvocationHandler h = new InvocationHandler() {
-
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- BeanInfo bi = Introspector.getBeanInfo(c, null);
- for (PropertyDescriptor pd : bi.getPropertyDescriptors()) {
- Method rm = pd.getReadMethod(), wm = pd.getWriteMethod();
- if (method.equals(rm))
- return Config.this.get(section2 + '/' + pd.getName()).to(rm.getGenericReturnType());
- if (method.equals(wm))
- return Config.this.set(section2 + '/' + pd.getName(), args[0]);
- }
- throw unsupportedOperationException("Unsupported interface method. method=''{0}''", method);
- }
- };
-
- return (T)Proxy.newProxyInstance(c.getClassLoader(), new Class[] { c }, h);
- }
-
- /**
* Returns <jk>true</jk> if this section contains the specified key and the key has a non-blank value.
*
* @param key The key.
diff --git a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Section.java b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Section.java
new file mode 100644
index 0000000..cfa98e0
--- /dev/null
+++ b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Section.java
@@ -0,0 +1,353 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file *
+// * to you 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.apache.juneau.config;
+
+import static org.apache.juneau.assertions.Assertions.*;
+import static org.apache.juneau.internal.ThrowableUtils.*;
+import static java.util.Optional.*;
+
+import java.beans.*;
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.collections.*;
+import org.apache.juneau.config.internal.*;
+import org.apache.juneau.parser.*;
+
+/**
+ * A single section in a config file.
+ */
+public class Section {
+
+ final Config config;
+ private final ConfigMap configMap;
+ final String name;
+
+ /**
+ * Constructor.
+ *
+ * @param config The config that this entry belongs to.
+ * @param configMap The map that this belongs to.
+ * @param name The section name of this entry.
+ */
+ protected Section(Config config, ConfigMap configMap, String name) {
+ this.config = config;
+ this.configMap = configMap;
+ this.name = name;
+ }
+
+ /**
+ * Returns <jk>true</jk> if this section exists.
+ *
+ * @return <jk>true</jk> if this section exists.
+ */
+ public boolean isPresent() {
+ return configMap.hasSection(name);
+ }
+
+ /**
+ * Shortcut for calling <code>toBean(sectionName, c, <jk>false</jk>)</code>.
+ *
+ * @param c The bean class to create.
+ * @return A new bean instance, or <jk>null</jk> if this section does not exist.
+ * @throws ParseException Malformed input encountered.
+ */
+ public <T> T toBean(Class<T> c) throws ParseException {
+ return toBean(c, false);
+ }
+
+ /**
+ * Shortcut for calling <code>asBean(sectionName, c, <jk>false</jk>)</code>.
+ *
+ * @param c The bean class to create.
+ * @return A new bean instance, or {@link Optional#empty()} if this section does not exist.
+ * @throws ParseException Malformed input encountered.
+ */
+ public <T> Optional<T> asBean(Class<T> c) throws ParseException {
+ return ofNullable(toBean(c));
+ }
+
+ /**
+ * Converts this config file section to the specified bean instance.
+ *
+ * <p>
+ * Key/value pairs in the config file section get copied as bean property values to the specified bean class.
+ *
+ * <h5 class='figure'>Example config file</h5>
+ * <p class='bcode w800'>
+ * <cs>[MyAddress]</cs>
+ * <ck>name</ck> = <cv>John Smith</cv>
+ * <ck>street</ck> = <cv>123 Main Street</cv>
+ * <ck>city</ck> = <cv>Anywhere</cv>
+ * <ck>state</ck> = <cv>NY</cv>
+ * <ck>zip</ck> = <cv>12345</cv>
+ * </p>
+ *
+ * <h5 class='figure'>Example bean</h5>
+ * <p class='bcode w800'>
+ * <jk>public class</jk> Address {
+ * public String name, street, city;
+ * public StateEnum state;
+ * public int zip;
+ * }
+ * </p>
+ *
+ * <h5 class='figure'>Example usage</h5>
+ * <p class='bcode w800'>
+ * Config cf = Config.<jsm>create</jsm>().name(<js>"MyConfig.cfg"</js>).build();
+ * Address myAddress = cf.getSection(<js>"MySection"</js>).toBean(Address.<jk>class</jk>);
+ * </p>
+ *
+ * @param c The bean class to create.
+ * @param ignoreUnknownProperties
+ * If <jk>false</jk>, throws a {@link ParseException} if the section contains an entry that isn't a bean property
+ * name.
+ * @return A new bean instance, or <jk>null</jk> if this section doesn't exist.
+ * @throws ParseException Unknown property was encountered in section.
+ */
+ public <T> T toBean(Class<T> c, boolean ignoreUnknownProperties) throws ParseException {
+ assertArgNotNull("c", c);
+ if (! isPresent()) return null;
+
+ Set<String> keys = configMap.getKeys(name);
+
+ BeanMap<T> bm = config.beanSession.newBeanMap(c);
+ for (String k : keys) {
+ BeanPropertyMeta bpm = bm.getPropertyMeta(k);
+ if (bpm == null) {
+ if (! ignoreUnknownProperties)
+ throw new ParseException("Unknown property ''{0}'' encountered in configuration section ''{1}''.", k, name);
+ } else {
+ bm.put(k, config.get(name + '/' + k).as(bpm.getClassMeta().getInnerClass()).orElse(null));
+ }
+ }
+
+ return bm.getBean();
+ }
+
+ /**
+ * Converts this config file section to the specified bean instance.
+ *
+ * <p>
+ * Key/value pairs in the config file section get copied as bean property values to the specified bean class.
+ *
+ * <h5 class='figure'>Example config file</h5>
+ * <p class='bcode w800'>
+ * <cs>[MyAddress]</cs>
+ * <ck>name</ck> = <cv>John Smith</cv>
+ * <ck>street</ck> = <cv>123 Main Street</cv>
+ * <ck>city</ck> = <cv>Anywhere</cv>
+ * <ck>state</ck> = <cv>NY</cv>
+ * <ck>zip</ck> = <cv>12345</cv>
+ * </p>
+ *
+ * <h5 class='figure'>Example bean</h5>
+ * <p class='bcode w800'>
+ * <jk>public class</jk> Address {
+ * public String name, street, city;
+ * public StateEnum state;
+ * public int zip;
+ * }
+ * </p>
+ *
+ * <h5 class='figure'>Example usage</h5>
+ * <p class='bcode w800'>
+ * Config cf = Config.<jsm>create</jsm>().name(<js>"MyConfig.cfg"</js>).build();
+ * Address myAddress = cf.getSection(<js>"MySection"</js>).asBean(Address.<jk>class</jk>).orElse(<jk>null</jk>);
+ * </p>
+ *
+ * @param c The bean class to create.
+ * @param ignoreUnknownProperties
+ * If <jk>false</jk>, throws a {@link ParseException} if the section contains an entry that isn't a bean property
+ * name.
+ * @return A new bean instance, or <jk>null</jk> if this section doesn't exist.
+ * @throws ParseException Unknown property was encountered in section.
+ */
+ public <T> Optional<T> asBean(Class<T> c, boolean ignoreUnknownProperties) throws ParseException {
+ return ofNullable(toBean(c, ignoreUnknownProperties));
+ }
+
+ /**
+ * Returns this section as a map.
+ *
+ * @return A new {@link OMap}, or <jk>null</jk> if this section doesn't exist.
+ */
+ public OMap toMap() {
+ if (! isPresent()) return null;
+
+ Set<String> keys = configMap.getKeys(name);
+
+ OMap om = new OMap();
+ for (String k : keys)
+ om.put(k, config.get(name + '/' + k).as(Object.class).orElse(null));
+ return om;
+ }
+
+ /**
+ * Returns this section as a map.
+ *
+ * @return A new {@link OMap}, or {@link Optional#empty()} if this section doesn't exist.
+ */
+ public Optional<OMap> asMap() {
+ return ofNullable(toMap());
+ }
+
+ /**
+ * Wraps this section inside a Java interface so that values in the section can be read and
+ * write using getters and setters.
+ *
+ * <h5 class='figure'>Example config file</h5>
+ * <p class='bcode w800'>
+ * <cs>[MySection]</cs>
+ * <ck>string</ck> = <cv>foo</cv>
+ * <ck>int</ck> = <cv>123</cv>
+ * <ck>enum</ck> = <cv>ONE</cv>
+ * <ck>bean</ck> = <cv>{foo:'bar',baz:123}</cv>
+ * <ck>int3dArray</ck> = <cv>[[[123,null],null],null]</cv>
+ * <ck>bean1d3dListMap</ck> = <cv>{key:[[[[{foo:'bar',baz:123}]]]]}</cv>
+ * </p>
+ *
+ * <h5 class='figure'>Example interface</h5>
+ * <p class='bcode w800'>
+ * <jk>public interface</jk> MyConfigInterface {
+ *
+ * String getString();
+ * <jk>void</jk> setString(String x);
+ *
+ * <jk>int</jk> getInt();
+ * <jk>void</jk> setInt(<jk>int</jk> x);
+ *
+ * MyEnum getEnum();
+ * <jk>void</jk> setEnum(MyEnum x);
+ *
+ * MyBean getBean();
+ * <jk>void</jk> setBean(MyBean x);
+ *
+ * <jk>int</jk>[][][] getInt3dArray();
+ * <jk>void</jk> setInt3dArray(<jk>int</jk>[][][] x);
+ *
+ * Map<String,List<MyBean[][][]>> getBean1d3dListMap();
+ * <jk>void</jk> setBean1d3dListMap(Map<String,List<MyBean[][][]>> x);
+ * }
+ * </p>
+ *
+ * <h5 class='figure'>Example usage</h5>
+ * <p class='bcode w800'>
+ * Config cf = Config.<jsm>create</jsm>().name(<js>"MyConfig.cfg"</js>).build();
+ *
+ * MyConfigInterface ci = cf.get(<js>"MySection"</js>).toInterface(MyConfigInterface.<jk>class</jk>);
+ *
+ * <jk>int</jk> myInt = ci.getInt();
+ *
+ * ci.setBean(<jk>new</jk> MyBean());
+ *
+ * cf.save();
+ * </p>
+ *
+ * <ul class='notes'>
+ * <li>Calls to setters when the configuration is read-only will cause {@link UnsupportedOperationException} to be thrown.
+ * </ul>
+ *
+ * @param c The proxy interface class.
+ * @return The proxy interface.
+ */
+ @SuppressWarnings("unchecked")
+ public <T> T toInterface(final Class<T> c) {
+ assertArgNotNull("c", c);
+
+ if (! c.isInterface())
+ throw illegalArgumentException("Class ''{0}'' passed to toInterface() is not an interface.", c.getName());
+
+ InvocationHandler h = new InvocationHandler() {
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ BeanInfo bi = Introspector.getBeanInfo(c, null);
+ for (PropertyDescriptor pd : bi.getPropertyDescriptors()) {
+ Method rm = pd.getReadMethod(), wm = pd.getWriteMethod();
+ if (method.equals(rm))
+ return config.get(name + '/' + pd.getName()).to(rm.getGenericReturnType());
+ if (method.equals(wm))
+ return config.set(name + '/' + pd.getName(), args[0]);
+ }
+ throw unsupportedOperationException("Unsupported interface method. method=''{0}''", method);
+ }
+ };
+
+ return (T)Proxy.newProxyInstance(c.getClassLoader(), new Class[] { c }, h);
+ }
+
+ /**
+ * Wraps this section inside a Java interface so that values in the section can be read and
+ * write using getters and setters.
+ *
+ * <h5 class='figure'>Example config file</h5>
+ * <p class='bcode w800'>
+ * <cs>[MySection]</cs>
+ * <ck>string</ck> = <cv>foo</cv>
+ * <ck>int</ck> = <cv>123</cv>
+ * <ck>enum</ck> = <cv>ONE</cv>
+ * <ck>bean</ck> = <cv>{foo:'bar',baz:123}</cv>
+ * <ck>int3dArray</ck> = <cv>[[[123,null],null],null]</cv>
+ * <ck>bean1d3dListMap</ck> = <cv>{key:[[[[{foo:'bar',baz:123}]]]]}</cv>
+ * </p>
+ *
+ * <h5 class='figure'>Example interface</h5>
+ * <p class='bcode w800'>
+ * <jk>public interface</jk> MyConfigInterface {
+ *
+ * String getString();
+ * <jk>void</jk> setString(String x);
+ *
+ * <jk>int</jk> getInt();
+ * <jk>void</jk> setInt(<jk>int</jk> x);
+ *
+ * MyEnum getEnum();
+ * <jk>void</jk> setEnum(MyEnum x);
+ *
+ * MyBean getBean();
+ * <jk>void</jk> setBean(MyBean x);
+ *
+ * <jk>int</jk>[][][] getInt3dArray();
+ * <jk>void</jk> setInt3dArray(<jk>int</jk>[][][] x);
+ *
+ * Map<String,List<MyBean[][][]>> getBean1d3dListMap();
+ * <jk>void</jk> setBean1d3dListMap(Map<String,List<MyBean[][][]>> x);
+ * }
+ * </p>
+ *
+ * <h5 class='figure'>Example usage</h5>
+ * <p class='bcode w800'>
+ * Config cf = Config.<jsm>create</jsm>().name(<js>"MyConfig.cfg"</js>).build();
+ *
+ * MyConfigInterface ci = cf.get(<js>"MySection"</js>).asInterface(MyConfigInterface.<jk>class</jk>).orElse(<jk>null</jk>);
+ *
+ * <jk>int</jk> myInt = ci.getInt();
+ *
+ * ci.setBean(<jk>new</jk> MyBean());
+ *
+ * cf.save();
+ * </p>
+ *
+ * <ul class='notes'>
+ * <li>Calls to setters when the configuration is read-only will cause {@link UnsupportedOperationException} to be thrown.
+ * </ul>
+ *
+ * @param c The proxy interface class.
+ * @return The proxy interface.
+ */
+ public <T> Optional<T> asInterface(final Class<T> c) {
+ return ofNullable(toInterface(c));
+ }
+}
diff --git a/juneau-microservice/juneau-microservice-core/src/main/java/org/apache/juneau/microservice/resources/ConfigResource.java b/juneau-microservice/juneau-microservice-core/src/main/java/org/apache/juneau/microservice/resources/ConfigResource.java
index 1cab30c..54da3c4 100755
--- a/juneau-microservice/juneau-microservice-core/src/main/java/org/apache/juneau/microservice/resources/ConfigResource.java
+++ b/juneau-microservice/juneau-microservice-core/src/main/java/org/apache/juneau/microservice/resources/ConfigResource.java
@@ -25,7 +25,6 @@ import org.apache.juneau.http.annotation.FormData;
import org.apache.juneau.http.annotation.Path;
import org.apache.juneau.http.annotation.Response;
import org.apache.juneau.http.annotation.Schema;
-import org.apache.juneau.parser.*;
import org.apache.juneau.rest.*;
import org.apache.juneau.rest.annotation.*;
import org.apache.juneau.http.response.*;
@@ -103,7 +102,7 @@ public class ConfigResource extends BasicRestServlet {
)
public OMap getConfigSection(
@Path("section") @Schema(d="Section name in config file.") String section
- ) throws SectionNotFound, BadConfig {
+ ) throws SectionNotFound {
return getSection(section);
}
@@ -121,7 +120,7 @@ public class ConfigResource extends BasicRestServlet {
public String getConfigEntry(
@Path("section") @Schema(d="Section name in config file.") String section,
@Path("key") @Schema(d="Key name in section.") String key
- ) throws SectionNotFound, BadConfig {
+ ) throws SectionNotFound {
return getSection(section).getString(key);
}
@@ -194,7 +193,7 @@ public class ConfigResource extends BasicRestServlet {
@Path("section") @Schema(d="Section name in config file.") String section,
@Path("key") @Schema(d="Key name in section.") String key,
@Body @Schema(d="New value for entry.") String value
- ) throws SectionNotFound, BadConfig {
+ ) throws SectionNotFound {
getContext().getConfig().set(section + '/' + key, value);
return getSection(section).getString(key);
@@ -213,28 +212,11 @@ public class ConfigResource extends BasicRestServlet {
}
}
- @Response @Schema(description="The configuration file contained syntax errors and could not be parsed.")
- private class BadConfig extends InternalServerError {
- private static final long serialVersionUID = 1L;
-
- BadConfig(Exception e) {
- super(e, "The configuration file contained syntax errors and could not be parsed.");
- }
- }
-
//-----------------------------------------------------------------------------------------------------------------
// Helper methods
//-----------------------------------------------------------------------------------------------------------------
- private OMap getSection(String name) throws SectionNotFound, BadConfig {
- OMap m;
- try {
- m = getContext().getConfig().getSectionAsMap(name);
- } catch (ParseException e) {
- throw new BadConfig(e);
- }
- if (m == null)
- throw new SectionNotFound();
- return m;
+ private OMap getSection(String name) throws SectionNotFound {
+ return getContext().getConfig().getSection(name).asMap().orElseThrow(SectionNotFound::new);
}
}
diff --git a/juneau-microservice/juneau-microservice-ftest/src/test/java/org/apache/juneau/rest/test/ConfigTest.java b/juneau-microservice/juneau-microservice-ftest/src/test/java/org/apache/juneau/rest/test/ConfigTest.java
index 2eaf940..691235d 100644
--- a/juneau-microservice/juneau-microservice-ftest/src/test/java/org/apache/juneau/rest/test/ConfigTest.java
+++ b/juneau-microservice/juneau-microservice-ftest/src/test/java/org/apache/juneau/rest/test/ConfigTest.java
@@ -40,7 +40,7 @@ public class ConfigTest extends RestTestcase {
Config cf = Config.create().memStore().build().load(m);
- assertObject(cf.getSectionAsMap("Test")).asJson().is("{int1:'1',int2:'[1,2,3]',int3:'1',int4:'1',int5:'-1',boolean1:'true',boolean2:'[true,true]',testManifestEntry:'test-value'}");
+ assertObject(cf.getSection("Test").toMap()).asJson().is("{int1:'1',int2:'[1,2,3]',int3:'1',int4:'1',int5:'-1',boolean1:'true',boolean2:'[true,true]',testManifestEntry:'test-value'}");
assertEquals("'1'", c.get(URL + "/Test%2Fint1/" + getName(String.class)).run().getBody().asString());
assertEquals("'[1,2,3]'", c.get(URL + "/Test%2Fint2/" + getName(String.class)).run().getBody().asString());
diff --git a/juneau-utest/src/test/java/org/apache/juneau/config/ConfigInterfaceTest.java b/juneau-utest/src/test/java/org/apache/juneau/config/ConfigInterfaceTest.java
index f7ad992..c691c69 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/config/ConfigInterfaceTest.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/config/ConfigInterfaceTest.java
@@ -31,7 +31,7 @@ public class ConfigInterfaceTest {
public ConfigInterfaceTest() throws Exception {
cf = Config.create().serializer(SimpleJsonSerializer.DEFAULT.copy().addBeanTypes().addRootType().build()).build();
- proxy = cf.getSectionAsInterface("A", ConfigInterface.class);
+ proxy = cf.getSection("A").toInterface(ConfigInterface.class);
}
diff --git a/juneau-utest/src/test/java/org/apache/juneau/config/ConfigTest.java b/juneau-utest/src/test/java/org/apache/juneau/config/ConfigTest.java
index f96bc98..24e5c8f 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/config/ConfigTest.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/config/ConfigTest.java
@@ -839,24 +839,24 @@ public class ConfigTest {
ABean a = null;
BBean b = null;
- a = c.getSectionAsBean("", ABean.class);
+ a = c.getSection("").toBean(ABean.class);
assertObject(a).asJson().is("{foo:'qux'}");
- a = c.getSectionAsBean("", ABean.class);
+ a = c.getSection("").toBean(ABean.class);
assertObject(a).asJson().is("{foo:'qux'}");
- a = c.getSectionAsBean("S", ABean.class);
+ a = c.getSection(null).toBean(ABean.class);
+ assertObject(a).asJson().is("{foo:'qux'}");
+ a = c.getSection("S").toBean(ABean.class);
assertObject(a).asJson().is("{foo:'baz'}");
- b = c.getSectionAsBean("", BBean.class);
+ b = c.getSection("").toBean(BBean.class);
assertObject(b).asJson().is("{foo:'qux'}");
- b = c.getSectionAsBean("", BBean.class);
+ b = c.getSection("").toBean(BBean.class);
assertObject(b).asJson().is("{foo:'qux'}");
- b = c.getSectionAsBean("S", BBean.class);
+ b = c.getSection("S").toBean(BBean.class);
assertObject(b).asJson().is("{foo:'baz'}");
- assertThrown(()->c.getSectionAsBean("T", ABean.class)).message().is("Unknown property 'bar' encountered in configuration section 'T'.");
- assertThrown(()->c.getSectionAsBean("T", BBean.class)).message().is("Unknown property 'bar' encountered in configuration section 'T'.");
- assertThrown(()->c.getSectionAsBean(null, ABean.class)).message().is("Argument 'section' cannot be null.");
- assertThrown(()->c.getSectionAsBean(null, BBean.class)).message().is("Argument 'section' cannot be null.");
+ assertThrown(()->c.getSection("T").toBean(ABean.class)).message().is("Unknown property 'bar' encountered in configuration section 'T'.");
+ assertThrown(()->c.getSection("T").toBean(BBean.class)).message().is("Unknown property 'bar' encountered in configuration section 'T'.");
}
//====================================================================================================
@@ -869,13 +869,13 @@ public class ConfigTest {
ABean a = null;
BBean b = null;
- a = c.getSectionAsBean("T", ABean.class, true);
+ a = c.getSection("T").toBean(ABean.class, true);
assertObject(a).asJson().is("{foo:'qux'}");
- b = c.getSectionAsBean("T", BBean.class, true);
+ b = c.getSection("T").toBean(BBean.class, true);
assertObject(b).asJson().is("{foo:'qux'}");
- assertThrown(()->c.getSectionAsBean("T", ABean.class, false)).message().is("Unknown property 'bar' encountered in configuration section 'T'.");
- assertThrown(()->c.getSectionAsBean("T", BBean.class, false)).message().is("Unknown property 'bar' encountered in configuration section 'T'.");
+ assertThrown(()->c.getSection("T").toBean(ABean.class, false)).message().is("Unknown property 'bar' encountered in configuration section 'T'.");
+ assertThrown(()->c.getSection("T").toBean(BBean.class, false)).message().is("Unknown property 'bar' encountered in configuration section 'T'.");
}
//====================================================================================================
@@ -885,13 +885,12 @@ public class ConfigTest {
public void getSectionAsMap() throws Exception {
Config c = init("a=1", "[S]", "b=2", "[T]");
- assertObject(c.getSectionAsMap("")).asJson().is("{a:'1'}");
- assertObject(c.getSectionAsMap("")).asJson().is("{a:'1'}");
- assertObject(c.getSectionAsMap("S")).asJson().is("{b:'2'}");
- assertObject(c.getSectionAsMap("T")).asJson().is("{}");
- assertNull(c.getSectionAsMap("U"));
-
- assertThrown(()->c.getSectionAsMap(null)).message().is("Argument 'section' cannot be null.");
+ assertObject(c.getSection("").toMap()).asJson().is("{a:'1'}");
+ assertObject(c.getSection("").toMap()).asJson().is("{a:'1'}");
+ assertObject(c.getSection(null).toMap()).asJson().is("{a:'1'}");
+ assertObject(c.getSection("S").toMap()).asJson().is("{b:'2'}");
+ assertObject(c.getSection("T").toMap()).asJson().is("{}");
+ assertNull(c.getSection("U").toMap());
}
//====================================================================================================
@@ -902,20 +901,22 @@ public class ConfigTest {
Config c = init("foo=qux", "[S]", "foo=baz", "[T]", "foo=qux", "bar=qux");
AInterface a = null;
- a = c.getSectionAsInterface("", AInterface.class);
+ a = c.getSection("").toInterface(AInterface.class);
+ assertEquals("qux", a.getFoo());
+
+ a = c.getSection("").toInterface(AInterface.class);
assertEquals("qux", a.getFoo());
- a = c.getSectionAsInterface("", AInterface.class);
+ a = c.getSection(null).toInterface(AInterface.class);
assertEquals("qux", a.getFoo());
- a = c.getSectionAsInterface("S", AInterface.class);
+ a = c.getSection("S").toInterface(AInterface.class);
assertEquals("baz", a.getFoo());
- a = c.getSectionAsInterface("T", AInterface.class);
+ a = c.getSection("T").toInterface(AInterface.class);
assertEquals("qux", a.getFoo());
- assertThrown(()->c.getSectionAsInterface("T", ABean.class)).message().is("Class 'org.apache.juneau.config.ConfigTest$ABean' passed to getSectionAsInterface() is not an interface.");
- assertThrown(()->c.getSectionAsInterface(null, AInterface.class)).message().is("Argument 'section' cannot be null.");
+ assertThrown(()->c.getSection("T").toInterface(ABean.class)).message().is("Class 'org.apache.juneau.config.ConfigTest$ABean' passed to toInterface() is not an interface.");
}
public static interface AInterface {
@@ -1424,15 +1425,15 @@ public class ConfigTest {
public void testGetSectionMap() throws Exception {
Config cf = init("[A]", "a1=1", "", "[D]", "d1=$C{A/a1}","d2=$S{X}");
- assertObject(cf.getSectionAsMap("A")).asJson().is("{a1:'1'}");
- assertNull(cf.getSectionAsMap("B"));
- assertObject(cf.getSectionAsMap("C")).asJson().is("null");
+ assertObject(cf.getSection("A").toMap()).asJson().is("{a1:'1'}");
+ assertNull(cf.getSection("B").toMap());
+ assertObject(cf.getSection("C").toMap()).asJson().is("null");
- OMap m = cf.getSectionAsMap("A");
+ OMap m = cf.getSection("A").toMap();
assertObject(m).asJson().is("{a1:'1'}");
System.setProperty("X", "x");
- m = cf.getSectionAsMap("D");
+ m = cf.getSection("D").toMap();
assertObject(m).asJson().is("{d1:'1',d2:'x'}");
System.clearProperty("X");
}