Java tutorial
/* * Copyright (C) 2008 feilong * * 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 com.feilong.core.util; import static org.apache.commons.lang3.StringUtils.EMPTY; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.util.Locale; import java.util.Map; import java.util.MissingResourceException; import java.util.Properties; import java.util.PropertyResourceBundle; import java.util.ResourceBundle; import java.util.TreeMap; import org.apache.commons.beanutils.converters.ArrayConverter; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.feilong.core.UncheckedIOException; import com.feilong.core.bean.BeanUtil; import com.feilong.core.bean.ConvertUtil; import com.feilong.core.text.MessageFormatUtil; import static com.feilong.core.Validator.isNullOrEmpty; import static com.feilong.core.bean.ConvertUtil.toMap; import static com.feilong.core.bean.ConvertUtil.toProperties; import static com.feilong.core.lang.reflect.ConstructorUtil.newInstance; /** * {@link java.util.ResourceBundle ResourceBundle} . * * <p> * ??,?? {@link ConvertUtil}???? * </p> * * <h3>??,</h3> * * <blockquote> * <p> * ?Message.properties?Message_zh_CN.properties?Message_zh_ CN.class 3,?<br> * ?,.<br> * ?Message_zh_CN.class?Message_zh_CN.properties?Message.properties.<br> * </p> * * <p> * ??,??:<br> * {@link "java.util.ResourceBundle#loadBundle(CacheKey, List, Control, boolean)"}<br> * {@link java.util.ResourceBundle.Control#newBundle(String, Locale, String, ClassLoader, boolean)} * </p> * </blockquote> * * @author <a href="http://feitianbenyue.iteye.com/">feilong</a> * @see MessageFormatUtil#format(String, Object...) * @see java.util.ResourceBundle * @see java.util.PropertyResourceBundle * @see java.util.ListResourceBundle * @see "org.springframework.core.io.support.LocalizedResourceHelper" * @since 1.4.0 */ public final class ResourceBundleUtil { /** The Constant LOGGER. */ private static final Logger LOGGER = LoggerFactory.getLogger(ResourceBundleUtil.class); /** Don't let anyone instantiate this class. */ private ResourceBundleUtil() { //AssertionError?. ?????. ???. //see Effective Java 2nd throw new AssertionError("No " + getClass().getName() + " instances for you!"); } // ****************************getValue************************************************* /** * ?Properties? , {@link java.util.ResourceBundle#getBundle(String)} ??. * * <p> * ????? <code>arguments</code> , {@link MessageFormatUtil#format(String, Object...)} ?? * </p> * * @param baseName * ???,<b>?+??</b>, <b>message.feilong-core-test</b> <span style="color:red">(??)</span>;<br> * ,,????,<b>message/feilong-core-test</b><span style="color:red">( "/")</span> * @param key * Properties??? * @param arguments * the arguments * @return ?, * <ul> * <li>key?,LOGGER.warn ,? {@link StringUtils#EMPTY}</li> * <li>key,valuenull empty,value</li> * </ul> * @throws NullPointerException * <code>baseName</code> <code>key</code> null * @throws IllegalArgumentException * <code>baseName</code> blank, <code>key</code> blank * @throws MissingResourceException * ? <code>baseName</code> ? * @see #getResourceBundle(String) * @see #getValue(ResourceBundle, String, Object...) * @since 1.8.1 support arguments param */ public static String getValue(String baseName, String key, Object... arguments) { ResourceBundle resourceBundle = getResourceBundle(baseName); return getValue(resourceBundle, key, arguments); } /** * ?Properties? , {@link java.util.ResourceBundle#getBundle(String)} ??. * * <p> * ????? <code>arguments</code> , {@link MessageFormatUtil#format(String, Object...)} ?? * </p> * * <h3>:</h3> * * <blockquote> * * <p> * ? <b>messages\feilong-core-test.properties</b> ,: * </p> * * <pre class="code"> * test.arguments=my name is {0},age is {1} * </pre> * * : * * <pre class="code"> * ResourceBundleUtil.getValueWithArguments("messages.feilong-core-test", "test.arguments", "feilong", "18") * </pre> * * <b>:</b> * * <pre class="code"> * my name is feilong,age is 18 * </pre> * * </blockquote> * * @param baseName * ???,<b>?+??</b>, <b>message.feilong-core-test</b> <span style="color:red">(??)</span>;<br> * ,,????,<b>message/feilong-core-test</b><span style="color:red">( "/")</span> * @param key * Properties??? * @param locale * the locale for which a resource bundle is desired,null, {@link Locale#getDefault()} * @param arguments * ?Object[]? * @return ?, * <ul> * <li>key?,LOGGER.warn ,? {@link StringUtils#EMPTY}</li> * <li>key,valuenull empty,value</li> * </ul> * ?, * <ul> * <li>key?,LOGGER.warn ,? {@link StringUtils#EMPTY}</li> * <li>key,valuenull empty,value</li> * </ul> * @throws NullPointerException * <code>baseName</code> <code>key</code> null * @throws IllegalArgumentException * <code>baseName</code> blank, <code>key</code> blank * @throws MissingResourceException * ? <code>baseName</code> ? * @see #getResourceBundle(String, Locale) * @see #getValue(ResourceBundle, String, Object...) */ public static String getValue(String baseName, String key, Locale locale, Object... arguments) { ResourceBundle resourceBundle = getResourceBundle(baseName, locale); return getValue(resourceBundle, key, arguments); } /** * ?Properties? , {@link java.util.ResourceBundle#getBundle(String)} ??. * * <p> * ????? <code>arguments</code> , {@link MessageFormatUtil#format(String, Object...)} ?? * </p> * * <h3>:</h3> * * <blockquote> * * <p> * ? messages\feilong-core-test.properties ,: * </p> * * <pre class="code"> * test.arguments=my name is {0},age is {1} * </pre> * * : * * <pre class="code"> * ResourceBundleUtil.getValueWithArguments(resourceBundle, "test.arguments", "feilong", "18") * </pre> * * <b>:</b> * * <pre class="code"> * my name is feilong,age is 18 * </pre> * * </blockquote> * * @param resourceBundle * the resource bundle * @param key * Properties??? * @param arguments * ?Object[]? * @return ?, * <ul> * <li>key?,LOGGER.warn ,? {@link StringUtils#EMPTY}</li> * <li>key,valuenull empty,value</li> * </ul> * @throws NullPointerException * <code>resourceBundle</code> <code>key</code> null * @throws IllegalArgumentException * <code>key</code> blank, {@link IllegalArgumentException} * @see java.util.ResourceBundle#getString(String) * @see MessageFormatUtil#format(String, Object...) * @since 1.8.1 support arguments param */ public static String getValue(ResourceBundle resourceBundle, String key, Object... arguments) { Validate.notNull(resourceBundle, "resourceBundle can't be null!"); Validate.notBlank(key, "key can't be null/empty!"); if (!resourceBundle.containsKey(key)) { LOGGER.warn("resourceBundle:[{}] don't containsKey:[{}]", resourceBundle, key); return EMPTY; } String value = resourceBundle.getString(key); if (isNullOrEmpty(value)) { LOGGER.trace("resourceBundle has key:[{}],but value is null/empty", key); } return isNullOrEmpty(value) ? EMPTY : MessageFormatUtil.format(value, arguments);// ? arguments null, } //*************************************************************************** /** * ??,k/v ?map. * * <p> * ?:JDK{@link java.util.PropertyResourceBundle}, hashmap??,<br> * log?,<span style="color:red"> TreeMap</span> * </p> * * @param baseName * ???,<b>?+??</b>, <b>message.feilong-core-test</b> <span style="color:red">(??)</span>;<br> * ,,????,<b>message/feilong-core-test</b><span style="color:red">( "/")</span> * @return <code>baseName</code> key value,{@link java.util.Collections#emptyMap()}<br> * ?,?keyvalue? {@link TreeMap} * @throws NullPointerException * <code>baseName</code> null * @throws IllegalArgumentException * <code>baseName</code> blank * @throws MissingResourceException * ? <code>baseName</code> ? * @see #readToMap(String, Locale) * @since 1.8.1 change name */ public static Map<String, String> readToMap(String baseName) { return readToMap(baseName, null); } /** * ??,k/v ?Properties. * * <h3>:</h3> * * <blockquote> * * <p> * classpath messages ? memcached.properties,: * </p> * * <pre class="code"> * #expiretime period in minutes * #? * * # ? ip - ? * memcached.serverlist=172.20.3-1.23:11211,172.20.31.22:11211 * memcached.poolname=sidsock2 * #?? * memcached.expiretime=180 * * memcached.serverweight=2 * * memcached.initconnection=10 * memcached.minconnection=5 * memcached.maxconnection=250 * * #??30??? * memcached.maintSleep=30 * * # * memcached.nagle=false * * #? * memcached.socketto=3000 * memcached.alivecheck=false * * </pre> * * <b> * ??: * </b> * * <pre class="code"> * Properties properties = ResourceBundleUtil.readToProperties("messages.memcached"); * LOGGER.debug(JsonUtil.format(properties)); * </pre> * * <b>:</b> * * <pre class="code"> { "memcached.serverlist": "172.20.3-1.23:11211,172.20.31.22:11211", "memcached.maxconnection": "250", "memcached.socketto": "3000", "memcached.initconnection": "10", "memcached.nagle": "false", "memcached.expiretime": "180", "memcached.maintSleep": "30", "memcached.alivecheck": "false", "memcached.serverweight": "2", "memcached.poolname": "sidsock2", "memcached.minconnection": "5" } * * </pre> * * </blockquote> * * @param baseName * ???,<b>?+??</b>, <b>message.feilong-core-test</b> <span style="color:red">(??)</span>;<br> * ,,????,<b>message/feilong-core-test</b><span style="color:red">( "/")</span> * @return <code>baseName</code> key value, <code>new Properties</code><br> * ?,?keyvalue? {@link Properties} * @throws NullPointerException * <code>baseName</code> null * @throws IllegalArgumentException * <code>baseName</code> blank * @throws MissingResourceException * ? <code>baseName</code> ? * @see #readToMap(String) * @see ConvertUtil#toProperties(Map) * @since 1.8.1 */ public static Properties readToProperties(String baseName) { return toProperties(readToMap(baseName)); } /** * ??,k/v ?map. * * <p> * ?:JDK{@link java.util.PropertyResourceBundle}, hashmap??,<br> * log?,<span style="color:red"> TreeMap</span> * </p> * * @param baseName * ???,<b>?+??</b>, <b>message.feilong-core-test</b> <span style="color:red">(??)</span>;<br> * ,,????,<b>message/feilong-core-test</b><span style="color:red">( "/")</span> * @param locale * the locale for which a resource bundle is desired,null, {@link Locale#getDefault()} * @return <code>baseName</code> key value,{@link java.util.Collections#emptyMap()}<br> * ?,?keyvalue? {@link TreeMap}<br> * * @throws NullPointerException * <code>baseName</code> null * @throws IllegalArgumentException * <code>baseName</code> blank * @throws MissingResourceException * ? <code>baseName</code> ? * @see #getResourceBundle(String, Locale) * @see java.util.ResourceBundle#getKeys() * @see MapUtils#toMap(ResourceBundle) * @since 1.8.1 change name */ public static Map<String, String> readToMap(String baseName, Locale locale) { ResourceBundle resourceBundle = getResourceBundle(baseName, locale); return toMap(resourceBundle); } /** * ?properties?,??aliasBean. * * <h3>:</h3> * * <blockquote> * * <p> * classpath messages ? memcached.properties,: * </p> * * <pre class="code"> * #expiretime period in minutes * #? * * # ? ip - ? * memcached.serverlist=172.20.3-1.23:11211,172.20.31.22:11211 * memcached.poolname=sidsock2 * #?? * memcached.expiretime=180 * * memcached.serverweight=2 * * memcached.initconnection=10 * memcached.minconnection=5 * memcached.maxconnection=250 * * #??30??? * memcached.maintSleep=30 * * # * memcached.nagle=false * * #? * memcached.socketto=3000 * memcached.alivecheck=false * * </pre> * * <p> * <b>aliasBean</b>?: * </p> * * <pre class="code"> * * public class DangaMemCachedConfig{ * * <span style="color:green">//** The serverlist.</span> * @Alias(name = "memcached.serverlist",sampleValue = "172.20.31.23:11211,172.20.31.22:11211") * private String[] serverList; * * <span style="color:green">//@Alias(name = "memcached.poolname",sampleValue = "sidsock2")</span> * private String poolName; * * <span style="color:green">//** The expire time ??.</span> * @Alias(name = "memcached.expiretime",sampleValue = "180") * private Integer expireTime; * * <span style="color:green">//** ??. </span> * @Alias(name = "memcached.serverweight",sampleValue = "2,1") * private Integer[] weight; * * <span style="color:green">//** The init connection. </span> * @Alias(name = "memcached.initconnection",sampleValue = "10") * private Integer initConnection; * * <span style="color:green">//** The min connection.</span> * @Alias(name = "memcached.minconnection",sampleValue = "5") * private Integer minConnection; * * <span style="color:green">//** The max connection. </span> * @Alias(name = "memcached.maxconnection",sampleValue = "250") * private Integer maxConnection; * * <span style="color:green">//** ?,?30?,??.</span> * @Alias(name = "memcached.maintSleep",sampleValue = "30") * private Integer maintSleep; * * <span style="color:green">//** . </span> * @Alias(name = "memcached.nagle",sampleValue = "false") * private Boolean nagle; * * <span style="color:green">//** ?.</span> * @Alias(name = "memcached.socketto",sampleValue = "3000") * private Integer socketTo; * * <span style="color:green">//** The alive check.</span> * @Alias(name = "memcached.alivecheck",sampleValue = "false") * private Boolean aliveCheck; * * <span style="color:green">//setter getter </span> * } * * </pre> * * <b> * ??: * </b> * * <pre class="code"> * DangaMemCachedConfig dangaMemCachedConfig = ResourceBundleUtil * .readPropertiesToAliasBean("messages.memcached", DangaMemCachedConfig.class); * LOGGER.debug(JsonUtil.format(dangaMemCachedConfig)); * </pre> * * <b>:</b> * * <pre class="code"> { "maxConnection": 250, "expireTime": 180, "serverList": [ "172.20.3-1.23", "11211", "172.20.31.22", "11211" ], "weight": [2], "nagle": false, "initConnection": 10, "aliveCheck": false, "poolName": "sidsock2", "maintSleep": 30, "socketTo": 3000, "minConnection": 5 } * * </pre> * * <p> * ??, properties?keyvaluestring,, ??,?bean? * </p> * * <p> * ?,?,? serverList ["172.20.3-1.23:11211","172.20.31.22:11211"],??,<br> * , {@link ArrayConverter} ? allowedChars ? <code>'.', '-'</code>,?? * </p> * * <p> * ?: * </p> * * <pre class="code"> * ArrayConverter arrayConverter = new ArrayConverter(String[].class, new StringConverter(), 2); * char[] allowedChars = { ':' }; * arrayConverter.setAllowedChars(allowedChars); * * BeanUtil.register(arrayConverter, String[].class); * * DangaMemCachedConfig dangaMemCachedConfig = ResourceBundleUtil * .readPropertiesToAliasBean("messages.memcached", DangaMemCachedConfig.class); * LOGGER.debug(JsonUtil.format(dangaMemCachedConfig)); * </pre> * * <b>:</b> * * <pre class="code"> { "maxConnection": 250, "expireTime": 180, "serverList": [ "172.20.3-1.23:11211", "172.20.31.22:11211" ], "weight": [2], "nagle": false, "initConnection": 10, "aliveCheck": false, "poolName": "sidsock2", "maintSleep": 30, "socketTo": 3000, "minConnection": 5 } * </pre> * * </blockquote> * * @param <T> * the generic type * @param baseName * ???,<b>?+??</b>, <b>message.feilong-core-test</b> <span style="color:red">(??)</span>;<br> * ,,????,<b>message/feilong-core-test</b><span style="color:red">( "/")</span> * @param aliasBeanClass * the alias bean class * @return the t * @throws NullPointerException * <code>baseName</code> <code>aliasBean</code> null * @throws IllegalArgumentException * <code>baseName</code> blank * @throws MissingResourceException * ? <code>baseName</code> ? * @see com.feilong.core.bean.BeanUtil#populateAliasBean(Object, Map) * @since 1.8.1 */ public static <T> T readToAliasBean(String baseName, Class<T> aliasBeanClass) { Validate.notBlank(baseName, "baseName can't be null/empty!"); Validate.notNull(aliasBeanClass, "aliasBeanClass can't be null!"); return BeanUtil.populateAliasBean(newInstance(aliasBeanClass), readToMap(baseName)); } //********************************getResourceBundle********************************************** /** * {@link Locale#getDefault()} {@link ResourceBundle}. * * @param baseName * ???,<b>?+??</b>, <b>message.feilong-core-test</b> <span style="color:red">(??)</span>;<br> * ,,????,<b>message/feilong-core-test</b><span style="color:red">( "/")</span> * @return ? <code>baseName</code> ?,?null {@link ResourceBundle} * @throws NullPointerException * <code>baseName</code> null * @throws IllegalArgumentException * <code>baseName</code> blank * @throws MissingResourceException * ? <code>baseName</code> ? * @see java.util.Locale#getDefault() * @see #getResourceBundle(String, Locale) */ public static ResourceBundle getResourceBundle(String baseName) { return getResourceBundle(baseName, null); } /** * {@link ResourceBundle}. * * @param baseName * ???,<b>?+??</b>, <b>message.feilong-core-test</b> <span style="color:red">(??)</span>;<br> * ,,????,<b>message/feilong-core-test</b><span style="color:red">( "/")</span> * @param locale * the locale for which a resource bundle is desired,null, {@link Locale#getDefault()} * @return ? <code>baseName</code> ?,?null {@link ResourceBundle} * @throws NullPointerException * <code>baseName</code> null * @throws IllegalArgumentException * <code>baseName</code> blank * @throws MissingResourceException * ? <code>baseName</code> ? * @see java.util.ResourceBundle#getBundle(String, Locale) */ public static ResourceBundle getResourceBundle(String baseName, Locale locale) { Validate.notBlank(baseName, "baseName can't be null/empty!"); return ResourceBundle.getBundle(baseName, ObjectUtils.defaultIfNull(locale, Locale.getDefault())); } //***************************************************************************** /** * ResourceBundle({@link PropertyResourceBundle}),????(file). * * <p> * ? <code>fileName</code>? * </p> * * <h3>:</h3> * * <blockquote> * * <pre class="code"> * * String mailReadFile = "E:\\DataCommon\\Files\\Java\\config\\mail-read.properties"; * * ResourceBundle resourceBundleRead = ResourceBundleUtil.getResourceBundleByFileName(mailReadFile); * * String mailServerHost = resourceBundleRead.getString("incoming.pop.hostname"); * </pre> * * </blockquote> * * @param fileName * ?,: "E:\\DataCommon\\Files\\Java\\config\\mail-read.properties" * @return the resource bundle,may be null<br> * <code>fileName</code> null, {@link NullPointerException}<br> * <code>fileName</code> blank, {@link IllegalArgumentException}<br> * @see java.util.PropertyResourceBundle#PropertyResourceBundle(InputStream) * @see ResourceBundleUtil#getResourceBundle(InputStream) * @since 1.0.9 */ public static ResourceBundle getResourceBundleByFileName(String fileName) { Validate.notBlank(fileName, "fileName can't be null/empty!"); try { return getResourceBundle(new FileInputStream(fileName)); } catch (FileNotFoundException e) { throw new UncheckedIOException(e); } } /** * ResourceBundle({@link PropertyResourceBundle}),????(file). * * @param inputStream * the input stream * @return <code>inputStream</code> null, {@link NullPointerException}<br> * ? {@link java.util.PropertyResourceBundle#PropertyResourceBundle(InputStream)} * @see java.util.PropertyResourceBundle#PropertyResourceBundle(InputStream) * @since 1.0.9 */ public static ResourceBundle getResourceBundle(InputStream inputStream) { Validate.notNull(inputStream, "inputStream can't be null!"); try { return new PropertyResourceBundle(inputStream); } catch (IOException e) { throw new UncheckedIOException(e); } } /** * resource bundle({@link PropertyResourceBundle}),????(file). * * @param reader * the reader * @return <code>reader</code> null, {@link NullPointerException}<br> * ? {@link java.util.PropertyResourceBundle#PropertyResourceBundle(Reader)} * @see java.util.PropertyResourceBundle#PropertyResourceBundle(Reader) * @since 1.0.9 */ public static ResourceBundle getResourceBundle(Reader reader) { Validate.notNull(reader, "reader can't be null!"); try { return new PropertyResourceBundle(reader); } catch (IOException e) { throw new UncheckedIOException(e); } } }