Props add toBean method

This commit is contained in:
Looly
2019-08-21 18:04:00 +08:00
parent 9228a195b5
commit 9ed6412bac
6 changed files with 186 additions and 29 deletions

View File

@@ -10,6 +10,7 @@
* 【extra】 邮件增加图片支持pr#495@Github * 【extra】 邮件增加图片支持pr#495@Github
* 【core】 MapUtil、CollUtil增加emptyIfNullissue#502@Github * 【core】 MapUtil、CollUtil增加emptyIfNullissue#502@Github
* 【core】 增加emptyIfNull等issue#503@Github * 【core】 增加emptyIfNull等issue#503@Github
* 【setting】 Props增加toBean方法issue#499@Github
### Bug修复 ### Bug修复
* 【http】 修复HttpRquest中body方法长度计算问题issue#I10UPG@Gitee * 【http】 修复HttpRquest中body方法长度计算问题issue#I10UPG@Gitee

View File

@@ -236,7 +236,10 @@ public class ReflectUtil {
public static void setFieldValue(Object obj, String fieldName, Object value) throws UtilException { public static void setFieldValue(Object obj, String fieldName, Object value) throws UtilException {
Assert.notNull(obj); Assert.notNull(obj);
Assert.notBlank(fieldName); Assert.notBlank(fieldName);
setFieldValue(obj, getField(obj.getClass(), fieldName), value);
final Field field = getField(obj.getClass(), fieldName);
Assert.notNull(field, "Field [{}] is not exist in [{}]", fieldName, obj.getClass().getName());
setFieldValue(obj, field, value);
} }
/** /**
@@ -249,7 +252,7 @@ public class ReflectUtil {
*/ */
public static void setFieldValue(Object obj, Field field, Object value) throws UtilException { public static void setFieldValue(Object obj, Field field, Object value) throws UtilException {
Assert.notNull(obj); Assert.notNull(obj);
Assert.notNull(field); Assert.notNull(field, "Field in [{}] not exist !", obj.getClass().getName());
field.setAccessible(true); field.setAccessible(true);
if(null != value) { if(null != value) {

View File

@@ -1,5 +1,7 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging> <packaging>jar</packaging>
@@ -25,5 +27,11 @@
<artifactId>hutool-log</artifactId> <artifactId>hutool-log</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@@ -14,6 +14,7 @@ import java.nio.file.WatchEvent;
import java.util.Date; import java.util.Date;
import java.util.Properties; import java.util.Properties;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
import cn.hutool.core.getter.BasicTypeGetter; import cn.hutool.core.getter.BasicTypeGetter;
@@ -31,9 +32,11 @@ import cn.hutool.core.io.watch.WatchMonitor;
import cn.hutool.core.io.watch.WatchUtil; import cn.hutool.core.io.watch.WatchUtil;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log; import cn.hutool.log.Log;
import cn.hutool.log.LogFactory; import cn.hutool.log.LogFactory;
import cn.hutool.log.StaticLog;
import cn.hutool.setting.SettingRuntimeException; import cn.hutool.setting.SettingRuntimeException;
/** /**
@@ -57,9 +60,9 @@ public final class Props extends Properties implements BasicTypeGetter<String>,
* 获得Classpath下的Properties文件 * 获得Classpath下的Properties文件
* *
* @param resource 资源相对Classpath的路径 * @param resource 资源相对Classpath的路径
* @return Properties * @return Props
*/ */
public static Properties getProp(String resource) { public static Props getProp(String resource) {
return new Props(resource); return new Props(resource);
} }
@@ -70,7 +73,7 @@ public final class Props extends Properties implements BasicTypeGetter<String>,
* @param charsetName 字符集 * @param charsetName 字符集
* @return Properties * @return Properties
*/ */
public static Properties getProp(String resource, String charsetName) { public static Props getProp(String resource, String charsetName) {
return new Props(resource, charsetName); return new Props(resource, charsetName);
} }
@@ -81,7 +84,7 @@ public final class Props extends Properties implements BasicTypeGetter<String>,
* @param charset 字符集 * @param charset 字符集
* @return Properties * @return Properties
*/ */
public static Properties getProp(String resource, Charset charset) { public static Props getProp(String resource, Charset charset) {
return new Props(resource, charset); return new Props(resource, charset);
} }
@@ -120,7 +123,7 @@ public final class Props extends Properties implements BasicTypeGetter<String>,
*/ */
public Props(String path, Charset charset) { public Props(String path, Charset charset) {
Assert.notBlank(path, "Blank properties file path !"); Assert.notBlank(path, "Blank properties file path !");
if(null != charset) { if (null != charset) {
this.charset = charset; this.charset = charset;
} }
this.load(ResourceUtil.getResourceObj(path)); this.load(ResourceUtil.getResourceObj(path));
@@ -187,7 +190,7 @@ public final class Props extends Properties implements BasicTypeGetter<String>,
*/ */
public Props(String path, Class<?> clazz, Charset charset) { public Props(String path, Class<?> clazz, Charset charset) {
Assert.notBlank(path, "Blank properties file path !"); Assert.notBlank(path, "Blank properties file path !");
if(null != charset) { if (null != charset) {
this.charset = charset; this.charset = charset;
} }
this.load(new ClassPathResource(path, clazz)); this.load(new ClassPathResource(path, clazz));
@@ -220,7 +223,7 @@ public final class Props extends Properties implements BasicTypeGetter<String>,
*/ */
public Props(URL propertiesUrl, Charset charset) { public Props(URL propertiesUrl, Charset charset) {
Assert.notNull(propertiesUrl, "Null properties URL !"); Assert.notNull(propertiesUrl, "Null properties URL !");
if(null != charset) { if (null != charset) {
this.charset = charset; this.charset = charset;
} }
this.load(new UrlResource(propertiesUrl)); this.load(new UrlResource(propertiesUrl));
@@ -276,7 +279,7 @@ public final class Props extends Properties implements BasicTypeGetter<String>,
// 先关闭之前的监听 // 先关闭之前的监听
this.watchMonitor.close(); this.watchMonitor.close();
} }
this.watchMonitor = WatchUtil.createModify(this.propertiesFileUrl, new SimpleWatcher(){ this.watchMonitor = WatchUtil.createModify(this.propertiesFileUrl, new SimpleWatcher() {
@Override @Override
public void onModify(WatchEvent<?> event, Path currentPath) { public void onModify(WatchEvent<?> event, Path currentPath) {
load(); load();
@@ -470,6 +473,86 @@ public final class Props extends Properties implements BasicTypeGetter<String>,
return (String) value; return (String) value;
} }
/**
* 将配置文件转换为Bean支持嵌套Bean<br>
* 支持的表达式:
*
* <pre>
* persion
* persion.name
* persons[3]
* person.friends[5].name
* ['person']['friends'][5]['name']
* </pre>
*
* @param beanClass Bean类
* @return Bean对象
* @since 4.6.3
*/
public <T> T toBean(Class<T> beanClass) {
return toBean(beanClass, null);
}
/**
* 将配置文件转换为Bean支持嵌套Bean<br>
* 支持的表达式:
*
* <pre>
* persion
* persion.name
* persons[3]
* person.friends[5].name
* ['person']['friends'][5]['name']
* </pre>
*
* @param beanClass Bean类
* @param prefix 公共前缀不指定前缀传null当指定前缀后非此前缀的属性被忽略
* @return Bean对象
* @since 4.6.3
*/
public <T> T toBean(Class<T> beanClass, String prefix) {
final T bean = ReflectUtil.newInstanceIfPossible(beanClass);
return fillBean(bean, prefix);
}
/**
* 将配置文件转换为Bean支持嵌套Bean<br>
* 支持的表达式:
*
* <pre>
* persion
* persion.name
* persons[3]
* person.friends[5].name
* ['person']['friends'][5]['name']
* </pre>
*
* @param bean Bean对象
* @param prefix 公共前缀不指定前缀传null当指定前缀后非此前缀的属性被忽略
* @return Bean对象
* @since 4.6.3
*/
public <T> T fillBean(T bean, String prefix) {
prefix = StrUtil.addSuffixIfNot(prefix, StrUtil.DOT);
String key;
for (java.util.Map.Entry<Object, Object> entry : this.entrySet()) {
key = (String) entry.getKey();
if(false == StrUtil.startWith(key, prefix)) {
// 非指定开头的属性忽略掉
continue;
}
try {
BeanUtil.setProperty(bean, StrUtil.subSuf(key, prefix.length()), entry.getValue());
} catch (Exception e) {
// 忽略注入失败的字段(这些字段可能用于其它配置)
StaticLog.debug("Ignore property: [{}]", key);
}
}
return bean;
}
// ----------------------------------------------------------------------- Get end // ----------------------------------------------------------------------- Get end
// ----------------------------------------------------------------------- Set start // ----------------------------------------------------------------------- Set start
@@ -489,7 +572,7 @@ public final class Props extends Properties implements BasicTypeGetter<String>,
* @param absolutePath 设置文件的绝对路径 * @param absolutePath 设置文件的绝对路径
* @throws IORuntimeException IO异常可能为文件未找到 * @throws IORuntimeException IO异常可能为文件未找到
*/ */
public void store(String absolutePath) throws IORuntimeException{ public void store(String absolutePath) throws IORuntimeException {
Writer writer = null; Writer writer = null;
try { try {
writer = FileUtil.getWriter(absolutePath, charset, false); writer = FileUtil.getWriter(absolutePath, charset, false);

View File

@@ -1,5 +1,8 @@
package cn.hutool.setting.test; package cn.hutool.setting.test;
import java.util.List;
import java.util.Map;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Ignore; import org.junit.Ignore;
@@ -8,21 +11,23 @@ import org.junit.Test;
import cn.hutool.log.LogFactory; import cn.hutool.log.LogFactory;
import cn.hutool.log.dialect.console.ConsoleLogFactory; import cn.hutool.log.dialect.console.ConsoleLogFactory;
import cn.hutool.setting.dialect.Props; import cn.hutool.setting.dialect.Props;
import lombok.Data;
/** /**
* Setting单元测试 * Setting单元测试
*
* @author Looly * @author Looly
* *
*/ */
public class PropsTest { public class PropsTest {
@Before @Before
public void init(){ public void init() {
LogFactory.setCurrentLogFactory(ConsoleLogFactory.class); LogFactory.setCurrentLogFactory(ConsoleLogFactory.class);
} }
@Test @Test
public void propTest(){ public void propTest() {
Props props = new Props("test.properties"); Props props = new Props("test.properties");
String user = props.getProperty("user"); String user = props.getProperty("user");
Assert.assertEquals(user, "root"); Assert.assertEquals(user, "root");
@@ -33,7 +38,7 @@ public class PropsTest {
@Test @Test
@Ignore @Ignore
public void propTestForAbsPAth(){ public void propTestForAbsPAth() {
Props props = new Props("d:/test.properties"); Props props = new Props("d:/test.properties");
String user = props.getProperty("user"); String user = props.getProperty("user");
Assert.assertEquals(user, "root"); Assert.assertEquals(user, "root");
@@ -41,4 +46,41 @@ public class PropsTest {
String driver = props.getStr("driver"); String driver = props.getStr("driver");
Assert.assertEquals(driver, "com.mysql.jdbc.Driver"); Assert.assertEquals(driver, "com.mysql.jdbc.Driver");
} }
@Test
public void toBeanTest() {
Props props = Props.getProp("to_bean_test.properties");
ConfigProperties cfg = props.toBean(ConfigProperties.class, "mail");
Assert.assertEquals("mailer@mail.com", cfg.getHost());
Assert.assertEquals(9000, cfg.getPort());
Assert.assertEquals("mailer@mail.com", cfg.getFrom());
Assert.assertEquals("john", cfg.getCredentials().getUsername());
Assert.assertEquals("password", cfg.getCredentials().getPassword());
Assert.assertEquals("SHA1", cfg.getCredentials().getAuthMethod());
Assert.assertEquals("true", cfg.getAdditionalHeaders().get("redelivery"));
Assert.assertEquals("true", cfg.getAdditionalHeaders().get("secure"));
Assert.assertEquals("admin@mail.com", cfg.getDefaultRecipients().get(0));
Assert.assertEquals("owner@mail.com", cfg.getDefaultRecipients().get(1));
}
@Data
public static class ConfigProperties {
private String host;
private int port;
private String from;
private Credentials credentials;
private List<String> defaultRecipients;
private Map<String, String> additionalHeaders;
}
@Data
public static class Credentials {
private String authMethod;
private String username;
private String password;
}
} }

View File

@@ -0,0 +1,20 @@
#Simple properties
mail.host=mailer@mail.com
mail.port=9000
mail.from=mailer@mail.com
#List properties
mail.defaultRecipients[0]=admin@mail.com
mail.defaultRecipients[1]=owner@mail.com
#Map Properties
mail.additionalHeaders.redelivery=true
mail.additionalHeaders.secure=true
#Object properties
mail.credentials.username=john
mail.credentials.password=password
mail.credentials.authMethod=SHA1
# ignore properties
mail.ignore.filed = balabala