提交 f6bb13d5 编写于 作者: C Calvin

#21 整理基础类的使用并更新文档

上级 03c5f2ba
......@@ -357,7 +357,9 @@
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!-- 在parent的profile的基础上进一步定义 -->
<!-- 支持taglib tld文件查找的必要设置 -->
<useSystemClassLoader>false</useSystemClassLoader>
<!-- 将mvn命令行传入的selenium driver参数传入surefire的JVM -->
<systemPropertyVariables>
<selenium.driver>${selenium.driver}</selenium.driver>
</systemPropertyVariables>
......
......@@ -6,13 +6,13 @@
<description>Shiro Configuration</description>
<!-- Shiro's main business-tier object for web-enabled applications -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" depends-on="userDao,groupDao">
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="shiroDbRealm" />
<property name="cacheManager" ref="cacheManager" />
</bean>
<!-- 項目自定义的Realm -->
<bean id="shiroDbRealm" class="org.springside.examples.miniweb.service.account.ShiroDbRealm">
<bean id="shiroDbRealm" class="org.springside.examples.miniweb.service.account.ShiroDbRealm" depends-on="userDao,groupDao">
<property name="accountManager" ref="accountManager"/>
</bean>
......
......@@ -25,7 +25,7 @@
<property name="suffix" value=".jsp"/>
</bean>
<!-- 支持 Shiro对Controller的AOP安全控制 begin-->
<!-- 支持 Shiro对Controller的方法级AOP安全控制 begin-->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
<property name="proxyTargetClass" value="true" />
</bean>
......
......@@ -522,7 +522,9 @@
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!-- 在parent的profile的基础上进一步定义 -->
<!-- 支持taglib tld文件查找的必要设置 -->
<useSystemClassLoader>false</useSystemClassLoader>
<!-- 将由mvn命令行-Dselenium.driver传到surefire的JVM中 -->
<systemPropertyVariables>
<selenium.driver>${selenium.driver}</selenium.driver>
</systemPropertyVariables>
......
......@@ -25,7 +25,9 @@ public class StringDemo {
/**
* Apache提供的最常用的Null Safe的函数。
* 另有一些与String一样,但Null Safe的函数如indexOf(),没有一一演示。
*
* 另有一些与String一样,但Null Safe的函数,没有一一演示。
*
*/
@Test
public void utilsByApache() {
......@@ -34,9 +36,11 @@ public class StringDemo {
assertFalse(StringUtils.isNotBlank(""));
assertFalse(StringUtils.isNotBlank(" "));
//default值
//null的default值
assertEquals("", StringUtils.defaultString(null));
assertEquals("defaultStr", StringUtils.defaultString(null, "defaultStr"));
assertEquals("defaultStr", StringUtils.defaultIfBlank(null, "defaultStr"));
assertEquals("defaultStr", StringUtils.defaultIfBlank("", "defaultStr"));
assertEquals("defaultStr", StringUtils.defaultIfBlank(" ", "defaultStr"));
//截取字符串
String input = "hahakaka";
......@@ -46,11 +50,18 @@ public class StringDemo {
result = StringUtils.substringAfterLast(input, "ha");
assertEquals("kaka", result);
assertEquals("haha", StringUtils.substringBetween("'haha'", "'"));
assertEquals("haha", StringUtils.substringBetween("{haha}", "{", "}"));
//join
List<String> inputList = Lists.newArrayList("a", "b", "c");
result = StringUtils.join(inputList, ",");
assertEquals("a,b,c", result);
//ignoreCase的比较函数:contains/startWith/EndWith/indexOf/lastIndexOf
assertTrue(StringUtils.containsIgnoreCase("Aaabbb", "aaa"));
assertEquals(0, StringUtils.indexOfIgnoreCase("Aaabbb", "aaa"));
///split
input = "a,b,c";
String[] resultArray = StringUtils.split(input, ",");
......@@ -63,15 +74,16 @@ public class StringDemo {
//超长部分变省略号
assertEquals("abcdefg", StringUtils.abbreviate("abcdefg", 7));
assertEquals("abc...", StringUtils.abbreviate("abcdefg", 6));
assertEquals("ab...", StringUtils.abbreviate("abcdefg", 5));
//首字母大写
result = StringUtils.capitalize("abc");
assertEquals("Abc", result);
assertEquals("Abc", StringUtils.capitalize("abc"));
assertEquals("abc", StringUtils.uncapitalize("Abc"));
}
/**
* Guava的高级版Joiner,Splitter的函数与Joiner类似而相反,不再演示。
* Guava的高级版Joiner,
*
* Splitter的函数与Joiner功能类似,不再演示。
*/
@Test
public void joinerByGuava() {
......@@ -101,7 +113,7 @@ public class StringDemo {
}
/**
* 好玩的CaseFormat转换,在spaceSize->space_size之间转换,比如数据库列名与Java属性
* 好玩的CaseFormat转换,在spaceSize->space_size之间转换,比如数据库表名与Java类名,变量名之间的转换
*/
@Test
public void caseFormatByGuava() {
......
......@@ -6,13 +6,13 @@
<description>Shiro安全配置</description>
<!-- Shiro's main business-tier object for web-enabled applications -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" depends-on="userJpaDao">
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="shiroDbRealm" />
<property name="cacheManager" ref="shiroCacheManager" />
</bean>
<!-- 項目自定义的Realm -->
<bean id="shiroDbRealm" class="org.springside.examples.showcase.security.ShiroDbRealm">
<bean id="shiroDbRealm" class="org.springside.examples.showcase.security.ShiroDbRealm" depends-on="userJpaDao">
<property name="accountManager" ref="accountManager"/>
<!-- 可配置cache token<->认证信息的cache,用于REST等需要频繁认证的场景 -->
<property name="authorizationCachingEnabled" value="true"/>
......
......@@ -12,6 +12,7 @@ import java.io.InputStream;
import java.util.Properties;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -63,38 +64,30 @@ public class PropertiesLoader {
}
/**
* 取出Integer类型的Property,但以System的Property优先.如果都為Null則返回0.
* 取出Integer类型的Property,但以System的Property优先.如果都為Null或内容错误則返回0.
*/
public Integer getInteger(String key) {
String strResult = getProperty(key);
if (strResult != null) {
return Integer.valueOf(strResult);
} else {
return 0;
}
return NumberUtils.toInt(strResult);
}
/**
* 取出Integer类型的Property,但以System的Property优先.如果都為Null則返回Default值.
* 取出Integer类型的Property,但以System的Property优先.如果都為Null或内容错误則返回Default值.
*/
public Integer getInteger(String key, Integer defaultValue) {
String strResult = getProperty(key);
if (strResult != null) {
return Integer.valueOf(strResult);
} else {
return defaultValue;
}
return NumberUtils.toInt(strResult, defaultValue);
}
/**
* 取出Boolean类型的Property,但以System的Property优先.如果都為Null則返回false.
* 取出Boolean类型的Property,但以System的Property优先.如果都為Null或内容不为true/false則返回false.
*/
public Boolean getBoolean(String key) {
return Boolean.valueOf(getProperty(key));
}
/**
* 取出Boolean类型的Property,但以System的Property优先.如果都為Null則返回Default值.
* 取出Boolean类型的Property,但以System的Property优先.如果都為Null則返回Default值,如果内容不为true/false则返回false.
*/
public Boolean getBoolean(String key, boolean defaultValue) {
String strResult = getProperty(key);
......
......@@ -8,6 +8,7 @@ package org.springside.modules.utils;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
......@@ -25,7 +26,11 @@ import org.slf4j.LoggerFactory;
*/
public class Reflections {
public static final String CGLIB_CLASS_SEPARATOR = "$$";
private static final String CGLIB_CLASS_SEPARATOR = "$$";
private static final String SETTER_PREFIX = "set";
private static final String GETTER_PREFIX = "get";
private static Logger logger = LoggerFactory.getLogger(Reflections.class);
......@@ -33,29 +38,17 @@ public class Reflections {
* 调用Getter方法.
*/
public static Object invokeGetter(Object obj, String propertyName) {
String getterMethodName = "get" + StringUtils.capitalize(propertyName);
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(propertyName);
return invokeMethod(obj, getterMethodName, new Class[] {}, new Object[] {});
}
/**
* 调用Setter方法,如果屬性是原始類型,需要使用帶propertyType的版本.
* 调用Setter方法, 仅匹配方法名。
*
* @see #invokeSetter(Object, String, Object, Class)
*/
public static void invokeSetter(Object obj, String propertyName, Object value) {
invokeSetter(obj, propertyName, value, null);
}
/**
* 调用Setter方法.
*
* @param propertyType 作为setter方法的输入参数类型查找Setter方法,为Null时使用value的Class替代.
*/
public static void invokeSetter(Object obj, String propertyName, Object value, Class<?> propertyType) {
Class<?> type = propertyType != null ? propertyType : value.getClass();
String setterMethodName = "set" + StringUtils.capitalize(propertyName);
invokeMethod(obj, setterMethodName, new Class[] { type }, new Object[] { value });
String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(propertyName);
invokeMethodByName(obj, setterMethodName, new Object[] { value });
}
/**
......@@ -95,25 +88,31 @@ public class Reflections {
}
/**
* 对于被cglib AOP过的对象, 取得真实的Class类型.
* 直接调用对象方法, 无视private/protected修饰符.
* 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用.
* 同时匹配方法名+参数类型,
*/
public static Class<?> getUserClass(Class<?> clazz) {
if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) {
Class<?> superClass = clazz.getSuperclass();
if (superClass != null && !Object.class.equals(superClass)) {
return superClass;
}
public static Object invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,
final Object[] args) {
Method method = getAccessibleMethod(obj, methodName, parameterTypes);
if (method == null) {
throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");
}
try {
return method.invoke(obj, args);
} catch (Exception e) {
throw convertReflectionExceptionToUnchecked(e);
}
return clazz;
}
/**
* 直接调用对象方法, 无视private/protected修饰符.
* 用于一次性调用的情况.
* 直接调用对象方法, 无视private/protected修饰符,
* 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用.
* 只匹配函数名,如果有多个同名函数调用第一个。
*/
public static Object invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,
final Object[] args) {
Method method = getAccessibleMethod(obj, methodName, parameterTypes);
public static Object invokeMethodByName(final Object obj, final String methodName, final Object[] args) {
Method method = getAccessibleMethodByName(obj, methodName);
if (method == null) {
throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");
}
......@@ -126,7 +125,7 @@ public class Reflections {
}
/**
* 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
* 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
*
* 如向上转型到Object仍无法找到, 返回null.
*/
......@@ -136,7 +135,7 @@ public class Reflections {
for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
try {
Field field = superClass.getDeclaredField(fieldName);
field.setAccessible(true);
makeAccessible(field);
return field;
} catch (NoSuchFieldException e) {//NOSONAR
// Field不在当前类定义,继续向上转型
......@@ -148,28 +147,70 @@ public class Reflections {
/**
* 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
* 如向上转型到Object仍无法找到, 返回null.
* 匹配函数名+参数类型。
*
* 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
*/
public static Method getAccessibleMethod(final Object obj, final String methodName,
final Class<?>... parameterTypes) {
Validate.notNull(obj, "object can't be null");
Validate.notBlank(methodName, "methodName can't be blank");
for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
try {
Method method = superClass.getDeclaredMethod(methodName, parameterTypes);
method.setAccessible(true);
Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
makeAccessible(method);
return method;
} catch (NoSuchMethodException e) {//NOSONAR
} catch (NoSuchMethodException e) {
// Method不在当前类定义,继续向上转型
}
}
return null;
}
/**
* 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
* 如向上转型到Object仍无法找到, 返回null.
* 只匹配函数名。
*
* 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
*/
public static Method getAccessibleMethodByName(final Object obj, final String methodName) {
Validate.notNull(obj, "object can't be null");
Validate.notBlank(methodName, "methodName can't be blank");
for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
Method[] methods = searchType.getDeclaredMethods();
for (Method method : methods) {
if (method.getName().equals(methodName)) {
makeAccessible(method);
return method;
}
}
}
return null;
}
/**
* 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的securityManager抱怨。
*/
public static void makeAccessible(Method method) {
if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
&& !method.isAccessible()) {
method.setAccessible(true);
}
}
/**
* 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的securityManager抱怨。
*/
public static void makeAccessible(Field field) {
if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || Modifier
.isFinal(field.getModifiers())) && !field.isAccessible()) {
field.setAccessible(true);
}
}
/**
* 通过反射, 获得Class定义中声明的父类的泛型参数的类型.
* 如无法找到, 返回Object.class.
......@@ -217,6 +258,19 @@ public class Reflections {
return (Class) params[index];
}
/**
* 对于被cglib AOP过的对象, 取得真实的Class类型.
*/
public static Class<?> getUnproxyClass(Class<?> clazz) {
if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) {
Class<?> superClass = clazz.getSuperclass();
if (superClass != null && !Object.class.equals(superClass)) {
return superClass;
}
}
return clazz;
}
/**
* 将反射时的checked exception转换为unchecked exception.
*/
......
......@@ -22,23 +22,24 @@ public class PropertiesLoaderTest {
@Test
public void notExistProperty() throws IOException {
Properties p = new PropertiesLoader("classpath:/notexist.properties").getProperties();
assertNull(p.getProperty("notexist"));
PropertiesLoader pl = new PropertiesLoader("classpath:/notexist.properties");
assertNull(pl.getProperty("notexist"));
assertEquals("defaultValue", p.getProperty("notexist", "defaultValue"));
assertEquals("defaultValue", pl.getProperty("notexist", "defaultValue"));
}
@Test
public void integerAndBooleanProperty() {
PropertiesLoader p = new PropertiesLoader("classpath:/test1.properties", "classpath:/test2.properties");
PropertiesLoader pl = new PropertiesLoader("classpath:/test1.properties", "classpath:/test2.properties");
assertEquals(new Integer(1), p.getInteger("p1"));
assertEquals(new Integer(0), p.getInteger("notExist"));
assertEquals(new Integer(100), p.getInteger("notExist", 100));
assertEquals(new Integer(1), pl.getInteger("p1"));
assertEquals(new Integer(0), pl.getInteger("notExist"));
assertEquals(new Integer(100), pl.getInteger("notExist", 100));
assertEquals(new Boolean(true), p.getBoolean("p4"));
assertEquals(new Boolean(false), p.getBoolean("notExist"));
assertEquals(new Boolean(true), p.getBoolean("notExist", true));
assertEquals(new Boolean(true), pl.getBoolean("p4"));
assertEquals(new Boolean(true), pl.getBoolean("p4", true));
assertEquals(new Boolean(false), pl.getBoolean("notExist"));
assertEquals(new Boolean(true), pl.getBoolean("notExist", true));
}
@Test
......
......@@ -23,7 +23,23 @@ public class ReflectionsTest {
//绕过将publicField+1的setter函数,直接设置publicField的原始值
Reflections.setFieldValue(bean, "publicField", 2);
assertEquals(2, bean.inspectPublicField());
try {
Reflections.getFieldValue(bean, "notExist");
fail("should throw exception here");
} catch (IllegalArgumentException e) {
}
try {
Reflections.setFieldValue(bean, "notExist", 2);
fail("should throw exception here");
} catch (IllegalArgumentException e) {
}
}
@Test
......@@ -32,19 +48,45 @@ public class ReflectionsTest {
assertEquals(bean.inspectPublicField() + 1, Reflections.invokeGetter(bean, "publicField"));
bean = new TestBean();
Reflections.invokeSetter(bean, "publicField", 10, int.class);
//通过setter的函数将+1
Reflections.invokeSetter(bean, "publicField", 10);
assertEquals(10 + 1, bean.inspectPublicField());
//非原始類型,可省略類型參數
Reflections.invokeSetter(bean, "name", "foo");
assertEquals("foo", bean.name);
}
@Test
public void invokeMethod() {
TestBean bean = new TestBean();
//使用函数名+参数类型的匹配
assertEquals("hello calvin", Reflections.invokeMethod(bean, "privateMethod", new Class[] { String.class },
new Object[] { "calvin" }));
//仅匹配函数名
assertEquals("hello calvin", Reflections.invokeMethodByName(bean, "privateMethod", new Object[] { "calvin" }));
//函数名错
try {
Reflections.invokeMethod(bean, "notExistMethod", new Class[] { String.class }, new Object[] { "calvin" });
fail("should throw exception here");
} catch (IllegalArgumentException e) {
}
//参数类型错
try {
Reflections.invokeMethod(bean, "privateMethod", new Class[] { Integer.class }, new Object[] { "calvin" });
fail("should throw exception here");
} catch (RuntimeException e) {
}
//函数名错
try {
Reflections.invokeMethodByName(bean, "notExistMethod", new Object[] { "calvin" });
fail("should throw exception here");
} catch (IllegalArgumentException e) {
}
}
@Test
......@@ -92,8 +134,6 @@ public class ReflectionsTest {
/** 有getter/setter的field */
private int publicField = 1;
private String name;
//通過getter函數會比屬性值+1
public int getPublicField() {
return publicField + 1;
......@@ -104,10 +144,6 @@ public class ReflectionsTest {
this.publicField = publicField + 1;
}
public void setName(String name) {
this.name = name;
}
public int inspectPrivateField() {
return privateField;
}
......
......@@ -54,8 +54,9 @@
<url>http://localhost:8081/nexus/content/groups/public</url>
</repository>
-->
<repository>
<id>springside-google</id>
<id>springside-googlecode</id>
<name>SpringSide Additional Repository at google</name>
<url>http://springside.googlecode.com/svn/springside4-repository/</url>
<snapshots>
......@@ -943,7 +944,7 @@
<!-- sonar插件 -->
<plugin>
<groupId>org.codehaus.sonar</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<artifactId>sonar-maven3-plugin</artifactId>
<version>3.0</version>
</plugin>
</plugins>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册