All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.juneau.config.Section Maven / Gradle / Ivy

// ***************************************************************************************************************************
// * 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.common.internal.ArgUtils.*;
import static org.apache.juneau.internal.CollectionUtils.*;
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 true if this section exists.
	 *
	 * @return true if this section exists.
	 */
	public boolean isPresent() {
		return configMap.hasSection(name);
	}

	/**
	 * Shortcut for calling asBean(sectionName, c, false).
	 *
	 * @param  The bean class to create.
	 * @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  Optional asBean(Class c) throws ParseException {
		return asBean(c, false);
	}

	/**
	 * Converts this config file section to the specified bean instance.
	 *
	 * 

* Key/value pairs in the config file section get copied as bean property values to the specified bean class. * *

Example config file
*

* [MyAddress] * name = John Smith * street = 123 Main Street * city = Anywhere * state = NY * zip = 12345 *

* *
Example bean
*

* public class Address { * public String name, street, city; * public StateEnum state; * public int zip; * } *

* *
Example usage
*

* Config config = Config.create().name("MyConfig.cfg").build(); * Address address = config.getSection("MySection").asBean(Address.class).orElse(null); *

* * @param The bean class to create. * @param c The bean class to create. * @param ignoreUnknownProperties * If false, throws a {@link ParseException} if the section contains an entry that isn't a bean property * name. * @return A new bean instance, or null if this section doesn't exist. * @throws ParseException Unknown property was encountered in section. */ public Optional asBean(Class c, boolean ignoreUnknownProperties) throws ParseException { assertArgNotNull("c", c); if (! isPresent()) return empty(); Set keys = configMap.getKeys(name); BeanMap 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 optional(bm.getBean()); } /** * Returns this section as a map. * * @return A new {@link JsonMap}, or {@link Optional#empty()} if this section doesn't exist. */ public Optional asMap() { if (! isPresent()) return empty(); Set keys = configMap.getKeys(name); JsonMap m = new JsonMap(); for (String k : keys) m.put(k, config.get(name + '/' + k).as(Object.class).orElse(null)); return optional(m); } /** * Wraps this section inside a Java interface so that values in the section can be read and * write using getters and setters. * *
Example config file
*

* [MySection] * string = foo * int = 123 * enum = ONE * bean = {foo:'bar',baz:123} * int3dArray = [[[123,null],null],null] * bean1d3dListMap = {key:[[[[{foo:'bar',baz:123}]]]]} *

* *
Example interface
*

* public interface MyConfigInterface { * * String getString(); * void setString(String value); * * int getInt(); * void setInt(int value); * * MyEnum getEnum(); * void setEnum(MyEnum value); * * MyBean getBean(); * void setBean(MyBean value); * * int[][][] getInt3dArray(); * void setInt3dArray(int[][][] value); * * Map<String,List<MyBean[][][]>> getBean1d3dListMap(); * void setBean1d3dListMap(Map<String,List<MyBean[][][]>> value); * } *

* *
Example usage
*

* Config config = Config.create().name("MyConfig.cfg").build(); * * MyConfigInterface ci = config.get("MySection").asInterface(MyConfigInterface.class).orElse(null); * * int myInt = ci.getInt(); * * ci.setBean(new MyBean()); * * ci.save(); *

* *
Notes:
    *
  • Calls to setters when the configuration is read-only will cause {@link UnsupportedOperationException} to be thrown. *
* * @param The proxy interface class. * @param c The proxy interface class. * @return The proxy interface. */ @SuppressWarnings("unchecked") public Optional asInterface(final Class c) { assertArgNotNull("c", c); if (!c.isInterface()) throw new IllegalArgumentException("Class '" + c.getName() + "' passed to toInterface() is not an interface."); return optional((T) Proxy.newProxyInstance(c.getClassLoader(), new Class[] { c }, (InvocationHandler) (proxy, method, args) -> { 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()).as(rm.getGenericReturnType()).orElse(null); if (method.equals(wm)) return config.set(name + '/' + pd.getName(), args[0]); } throw new UnsupportedOperationException("Unsupported interface method. method='" + method + "'"); })); } /** * Copies the entries in this section to the specified bean by calling the public setters on that bean. * * @param bean The bean to set the properties on. * @param ignoreUnknownProperties * If true, don't throw an {@link IllegalArgumentException} if this section contains a key that doesn't * correspond to a setter method. * @return An object map of the changes made to the bean. * @throws ParseException If parser was not set on this config file or invalid properties were found in the section. * @throws UnsupportedOperationException If configuration is read only. */ public Section writeToBean(Object bean, boolean ignoreUnknownProperties) throws ParseException { assertArgNotNull("bean", bean); if (! isPresent()) throw new IllegalArgumentException("Section '"+name+"' not found in configuration."); Set keys = configMap.getKeys(name); BeanMap bm = config.beanSession.toBeanMap(bean); 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 this; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy