This commit is contained in:
Looly 2022-11-13 19:50:05 +08:00
parent a78619502e
commit 7e28a55c75
5 changed files with 121 additions and 25 deletions

View File

@ -8,6 +8,7 @@ import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.classloader.ClassLoaderUtil; import cn.hutool.core.classloader.ClassLoaderUtil;
import cn.hutool.core.text.StrUtil; import cn.hutool.core.text.StrUtil;
import cn.hutool.core.net.url.URLUtil; import cn.hutool.core.net.url.URLUtil;
import cn.hutool.core.util.ObjUtil;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
@ -174,9 +175,26 @@ public class ResourceUtil {
* @since 4.1.5 * @since 4.1.5
*/ */
public static EnumerationIter<URL> getResourceUrlIter(final String resource) { public static EnumerationIter<URL> getResourceUrlIter(final String resource) {
return getResourceUrlIter(resource, null);
}
/**
* 获取指定路径下的资源Iterator<br>
* 路径格式必须为目录格式,/分隔例如:
*
* <pre>
* config/a
* spring/xml
* </pre>
*
* @param resource 资源路径
* @param classLoader {@link ClassLoader}
* @return 资源列表
*/
public static EnumerationIter<URL> getResourceUrlIter(final String resource, final ClassLoader classLoader) {
final Enumeration<URL> resources; final Enumeration<URL> resources;
try { try {
resources = ClassLoaderUtil.getClassLoader().getResources(resource); resources = ObjUtil.defaultIfNull(classLoader, ClassLoaderUtil.getClassLoader()).getResources(resource);
} catch (final IOException e) { } catch (final IOException e) {
throw new IORuntimeException(e); throw new IORuntimeException(e);
} }
@ -233,4 +251,30 @@ public class ResourceUtil {
public static Resource getResource(final File file) { public static Resource getResource(final File file) {
return new FileResource(file); return new FileResource(file);
} }
/**
* 获取同名的所有资源
*
* @param resource 资源名
* @return {@link MultiResource}
*/
public static MultiResource getResources(final String resource) {
return getResources(resource, null);
}
/**
* 获取同名的所有资源
*
* @param resource 资源名
* @param classLoader {@link ClassLoader}{@code null}表示使用默认的当前上下文ClassLoader
* @return {@link MultiResource}
*/
public static MultiResource getResources(final String resource, final ClassLoader classLoader) {
final EnumerationIter<URL> iter = getResourceUrlIter(resource, classLoader);
final MultiResource resources = new MultiResource();
for (final URL url : iter) {
resources.add(getResource(url));
}
return resources;
}
} }

View File

@ -37,7 +37,7 @@ public interface ForestMap<K, V> extends Map<K, TreeEntry<K, V>> {
* @see #putNode(Object, Object) * @see #putNode(Object, Object)
*/ */
@Override @Override
default TreeEntry<K, V> put(K key, TreeEntry<K, V> node) { default TreeEntry<K, V> put(final K key, final TreeEntry<K, V> node) {
return putNode(key, node.getValue()); return putNode(key, node.getValue());
} }
@ -47,7 +47,7 @@ public interface ForestMap<K, V> extends Map<K, TreeEntry<K, V>> {
* @param treeEntryMap 节点集合 * @param treeEntryMap 节点集合
*/ */
@Override @Override
default void putAll(Map<? extends K, ? extends TreeEntry<K, V>> treeEntryMap) { default void putAll(final Map<? extends K, ? extends TreeEntry<K, V>> treeEntryMap) {
if (CollUtil.isEmpty(treeEntryMap)) { if (CollUtil.isEmpty(treeEntryMap)) {
return; return;
} }
@ -73,7 +73,7 @@ public interface ForestMap<K, V> extends Map<K, TreeEntry<K, V>> {
* @param ignoreNullNode 是否获取到的key为null的子节点/父节点 * @param ignoreNullNode 是否获取到的key为null的子节点/父节点
*/ */
default <C extends Collection<V>> void putAllNode( default <C extends Collection<V>> void putAllNode(
C values, Function<V, K> keyGenerator, Function<V, K> parentKeyGenerator, boolean ignoreNullNode) { final C values, final Function<V, K> keyGenerator, final Function<V, K> parentKeyGenerator, final boolean ignoreNullNode) {
if (CollUtil.isEmpty(values)) { if (CollUtil.isEmpty(values)) {
return; return;
} }
@ -137,7 +137,7 @@ public interface ForestMap<K, V> extends Map<K, TreeEntry<K, V>> {
* @param childKey 子节点的key * @param childKey 子节点的key
* @param childValue 子节点的值 * @param childValue 子节点的值
*/ */
default void putLinkedNodes(K parentKey, V parentValue, K childKey, V childValue) { default void putLinkedNodes(final K parentKey, final V parentValue, final K childKey, final V childValue) {
putNode(parentKey, parentValue); putNode(parentKey, parentValue);
putNode(childKey, childValue); putNode(childKey, childValue);
linkNodes(parentKey, childKey); linkNodes(parentKey, childKey);
@ -162,7 +162,7 @@ public interface ForestMap<K, V> extends Map<K, TreeEntry<K, V>> {
* @param parentKey 父节点的key * @param parentKey 父节点的key
* @param childKey 子节点的key * @param childKey 子节点的key
*/ */
default void linkNodes(K parentKey, K childKey) { default void linkNodes(final K parentKey, final K childKey) {
linkNodes(parentKey, childKey, null); linkNodes(parentKey, childKey, null);
} }
@ -192,7 +192,7 @@ public interface ForestMap<K, V> extends Map<K, TreeEntry<K, V>> {
* @param key 指定节点的key * @param key 指定节点的key
* @return 节点 * @return 节点
*/ */
default Set<TreeEntry<K, V>> getTreeNodes(K key) { default Set<TreeEntry<K, V>> getTreeNodes(final K key) {
final TreeEntry<K, V> target = get(key); final TreeEntry<K, V> target = get(key);
if (ObjUtil.isNull(target)) { if (ObjUtil.isNull(target)) {
return Collections.emptySet(); return Collections.emptySet();
@ -209,7 +209,7 @@ public interface ForestMap<K, V> extends Map<K, TreeEntry<K, V>> {
* @param key 指定节点的key * @param key 指定节点的key
* @return 节点 * @return 节点
*/ */
default TreeEntry<K, V> getRootNode(K key) { default TreeEntry<K, V> getRootNode(final K key) {
return Opt.ofNullable(get(key)) return Opt.ofNullable(get(key))
.map(TreeEntry::getRoot) .map(TreeEntry::getRoot)
.orElse(null); .orElse(null);
@ -222,7 +222,7 @@ public interface ForestMap<K, V> extends Map<K, TreeEntry<K, V>> {
* @param key 指定节点的key * @param key 指定节点的key
* @return 节点 * @return 节点
*/ */
default TreeEntry<K, V> getDeclaredParentNode(K key) { default TreeEntry<K, V> getDeclaredParentNode(final K key) {
return Opt.ofNullable(get(key)) return Opt.ofNullable(get(key))
.map(TreeEntry::getDeclaredParent) .map(TreeEntry::getDeclaredParent)
.orElse(null); .orElse(null);
@ -235,7 +235,7 @@ public interface ForestMap<K, V> extends Map<K, TreeEntry<K, V>> {
* @param parentKey 指定父节点key * @param parentKey 指定父节点key
* @return 节点 * @return 节点
*/ */
default TreeEntry<K, V> getParentNode(K key, K parentKey) { default TreeEntry<K, V> getParentNode(final K key, final K parentKey) {
return Opt.ofNullable(get(key)) return Opt.ofNullable(get(key))
.map(t -> t.getParent(parentKey)) .map(t -> t.getParent(parentKey))
.orElse(null); .orElse(null);
@ -248,7 +248,7 @@ public interface ForestMap<K, V> extends Map<K, TreeEntry<K, V>> {
* @param parentKey 指定父节点的key * @param parentKey 指定父节点的key
* @return 是否 * @return 是否
*/ */
default boolean containsParentNode(K key, K parentKey) { default boolean containsParentNode(final K key, final K parentKey) {
return Opt.ofNullable(get(key)) return Opt.ofNullable(get(key))
.map(m -> m.containsParent(parentKey)) .map(m -> m.containsParent(parentKey))
.orElse(false); .orElse(false);
@ -260,7 +260,7 @@ public interface ForestMap<K, V> extends Map<K, TreeEntry<K, V>> {
* @param key 节点的key * @param key 节点的key
* @return 节点值若节点不存在或节点值为null都将返回null * @return 节点值若节点不存在或节点值为null都将返回null
*/ */
default V getNodeValue(K key) { default V getNodeValue(final K key) {
return Opt.ofNullable(get(key)) return Opt.ofNullable(get(key))
.map(TreeEntry::getValue) .map(TreeEntry::getValue)
.get(); .get();
@ -275,7 +275,7 @@ public interface ForestMap<K, V> extends Map<K, TreeEntry<K, V>> {
* @param childKey 子节点 * @param childKey 子节点
* @return 是否 * @return 是否
*/ */
default boolean containsChildNode(K parentKey, K childKey) { default boolean containsChildNode(final K parentKey, final K childKey) {
return Opt.ofNullable(get(parentKey)) return Opt.ofNullable(get(parentKey))
.map(m -> m.containsChild(childKey)) .map(m -> m.containsChild(childKey))
.orElse(false); .orElse(false);
@ -288,7 +288,7 @@ public interface ForestMap<K, V> extends Map<K, TreeEntry<K, V>> {
* @param key key * @param key key
* @return 节点 * @return 节点
*/ */
default Collection<TreeEntry<K, V>> getDeclaredChildNodes(K key) { default Collection<TreeEntry<K, V>> getDeclaredChildNodes(final K key) {
return Opt.ofNullable(get(key)) return Opt.ofNullable(get(key))
.map(TreeEntry::getDeclaredChildren) .map(TreeEntry::getDeclaredChildren)
.map(Map::values) .map(Map::values)
@ -302,7 +302,7 @@ public interface ForestMap<K, V> extends Map<K, TreeEntry<K, V>> {
* @param key key * @param key key
* @return 该节点的全部子节点 * @return 该节点的全部子节点
*/ */
default Collection<TreeEntry<K, V>> getChildNodes(K key) { default Collection<TreeEntry<K, V>> getChildNodes(final K key) {
return Opt.ofNullable(get(key)) return Opt.ofNullable(get(key))
.map(TreeEntry::getChildren) .map(TreeEntry::getChildren)
.map(Map::values) .map(Map::values)

View File

@ -697,7 +697,6 @@ public class Setting extends AbsSetting implements Map<String, String> {
* *
* @return 默认分组空分组中的所有键列表 * @return 默认分组空分组中的所有键列表
*/ */
@SuppressWarnings("NullableProblems")
@Override @Override
public Set<String> keySet() { public Set<String> keySet() {
return this.groupedMap.keySet(DEFAULT_GROUP); return this.groupedMap.keySet(DEFAULT_GROUP);
@ -708,7 +707,6 @@ public class Setting extends AbsSetting implements Map<String, String> {
* *
* @return 默认分组空分组中的所有值列表 * @return 默认分组空分组中的所有值列表
*/ */
@SuppressWarnings("NullableProblems")
@Override @Override
public Collection<String> values() { public Collection<String> values() {
return this.groupedMap.values(DEFAULT_GROUP); return this.groupedMap.values(DEFAULT_GROUP);
@ -719,7 +717,6 @@ public class Setting extends AbsSetting implements Map<String, String> {
* *
* @return 默认分组空分组中的所有键值对列表 * @return 默认分组空分组中的所有键值对列表
*/ */
@SuppressWarnings("NullableProblems")
@Override @Override
public Set<Entry<String, String>> entrySet() { public Set<Entry<String, String>> entrySet() {
return this.groupedMap.entrySet(DEFAULT_GROUP); return this.groupedMap.entrySet(DEFAULT_GROUP);

View File

@ -23,7 +23,6 @@ import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.ObjUtil;
import cn.hutool.log.StaticLog; import cn.hutool.log.StaticLog;
import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.Writer; import java.io.Writer;
@ -190,12 +189,7 @@ public final class Props extends Properties implements TypeGetter<CharSequence>
public void load(final Resource resource) { public void load(final Resource resource) {
Assert.notNull(resource, "Props resource must be not null!"); Assert.notNull(resource, "Props resource must be not null!");
this.resource = resource; this.resource = resource;
PropsLoaderUtil.loadTo(this, resource, this.charset);
try (final BufferedReader reader = resource.getReader(charset)) {
super.load(reader);
} catch (final IOException e) {
throw new IORuntimeException(e);
}
} }
/** /**

View File

@ -0,0 +1,61 @@
package cn.hutool.setting.dialect;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.resource.Resource;
import cn.hutool.core.io.resource.ResourceUtil;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Properties;
/**
* {@link Properties} 资源内容加载工具
*
* @author looly
* @since 6.0.0
*/
public class PropsLoaderUtil {
/**
* 加载配置文件内容到{@link Properties}<br>
* 需要注意的是如果资源文件的扩展名是.xml会调用{@link Properties#loadFromXML(InputStream)} 读取
*
* @param properties {@link Properties}文件
* @param resource 资源
* @param charset 编码对XML无效
*/
public static void loadTo(final Properties properties, final Resource resource, final Charset charset) {
final String filename = resource.getName();
if (filename != null && filename.endsWith(".xml")) {
// XML
try (final InputStream in = resource.getStream()) {
properties.loadFromXML(in);
} catch (final IOException e) {
throw new IORuntimeException(e);
}
} else {
// .properties
try (final BufferedReader reader = resource.getReader(charset)) {
properties.load(reader);
} catch (final IOException e) {
throw new IORuntimeException(e);
}
}
}
/**
* 加载指定名称的所有配置文件内容到{@link Properties}
*
* @param properties {@link Properties}文件
* @param resourceName 资源名可以是相对classpath的路径也可以是绝对路径
* @param classLoader {@link ClassLoader}{@code null}表示使用默认的当前上下文ClassLoader
* @param charset 编码对XML无效
*/
public static void loadAllTo(final Properties properties, final String resourceName, final ClassLoader classLoader, final Charset charset) {
for (final Resource resource : ResourceUtil.getResources(resourceName, classLoader)) {
loadTo(properties, resource, charset);
}
}
}