下面是我使用Java反射API构建的解决方案的说明。我已经在下面发布了工作代码(并附带其指向github的url)。该解决方案主要使用以下内容:
- Java反射API
- 独立处理Java集合
- 递归
首先,我使用
Introspector
来查看
Class
的
readMethods
,省略了为
Object
定义的方法。
for (PropertyDescriptor propertyDescriptor : Introspector
.getBeanInfo(c, Object.class).getPropertyDescriptors()) {
Method method = propertyDescriptor.getReadMethod()
案例
- 如果当前的
Property
级别是 String
类型
- 如果它是一个
Object
属性数组
- 如果它是一个
String
数组
- 如果它是 Java
Collection
类型
- 为
Map
单独设置特殊条件来处理其 keys 和 values
此实用工具使用 Java Reflection API 遍历对象图,遵循 getters 和 setters 的规范语法,并递归地修剪所有遇到的字符串。
代码
整个实用类及主测试类(和自定义数据类型/POJO)在 我的github 上。
用法:
myObj = (MyObject) SpaceUtil.trimReflective(myObj);
Util方法:
public static Object trimReflective(Object object) throws Exception {
if (object == null)
return null;
Class<? extends Object> c = object.getClass();
try {
for (PropertyDescriptor propertyDescriptor : Introspector
.getBeanInfo(c, Object.class).getPropertyDescriptors()) {
Method method = propertyDescriptor.getReadMethod();
String name = method.getName();
if (method.getReturnType().equals(String.class)) {
String property = (String) method.invoke(object);
if (property != null) {
Method setter = c.getMethod("set" + name.substring(3),
new Class<?>[] { String.class });
if (setter != null)
setter.invoke(object, property.trim());
}
}
if (method.getReturnType().isArray()
&& !method.getReturnType().isPrimitive()
&& !method.getReturnType().equals(String[].class)
&& !method.getReturnType().equals(byte[].class)) {
System.out.println(method.getReturnType());
if (method.invoke(object) instanceof Object[]) {
Object[] objectArray = (Object[]) method.invoke(object);
if (objectArray != null) {
for (Object obj : (Object[]) objectArray) {
trimReflective(obj);
}
}
}
}
if (method.getReturnType().equals(String[].class)) {
String[] propertyArray = (String[]) method.invoke(object);
if (propertyArray != null) {
Method setter = c.getMethod("set" + name.substring(3),
new Class<?>[] { String[].class });
if (setter != null) {
String[] modifiedArray = new String[propertyArray.length];
for (int i = 0; i < propertyArray.length; i++)
if (propertyArray[i] != null)
modifiedArray[i] = propertyArray[i].trim();
setter.invoke(object,
new Object[] { modifiedArray });
}
}
}
if (Collection.class.isAssignableFrom(method.getReturnType())) {
Collection collectionProperty = (Collection) method
.invoke(object);
if (collectionProperty != null) {
for (int index = 0; index < collectionProperty.size(); index++) {
if (collectionProperty.toArray()[index] instanceof String) {
String element = (String) collectionProperty
.toArray()[index];
if (element != null) {
if (collectionProperty instanceof List) {
((List) collectionProperty).set(index,
element.trim());
} else {
collectionProperty.remove(element);
collectionProperty.add(element.trim());
}
}
} else {
trimReflective(collectionProperty.toArray()[index]);
}
}
}
}
if (method.getReturnType().equals(Map.class)) {
Map mapProperty = (Map) method.invoke(object);
if (mapProperty != null) {
for (int index = 0; index < mapProperty.keySet().size(); index++) {
if (mapProperty.keySet().toArray()[index] instanceof String) {
String element = (String) mapProperty.keySet()
.toArray()[index];
if (element != null) {
mapProperty.put(element.trim(),
mapProperty.get(element));
mapProperty.remove(element);
}
} else {
trimReflective(mapProperty.get(index));
}
}
for (Map.Entry entry : (Set<Map.Entry>) mapProperty
.entrySet()) {
if (entry.getValue() instanceof String) {
String element = (String) entry.getValue();
if (element != null) {
entry.setValue(element.trim());
}
} else {
trimReflective(entry.getValue());
}
}
}
} else {
Object property = (Object) method.invoke(object);
if (property != null) {
trimReflective(property);
}
}
}
} catch (Exception e) {
throw new Exception("Strings cannot be trimmed because: ", e);
}
return object;
}
测试
我还有一个测试类,它创建了一个相对复杂的对象。测试类有不同的场景,涵盖了以下内容:
String
属性
- 作为自定义数据类型的属性,其内部又具有
String
属性
- 作为自定义数据类型的属性,其内部又具有自定义数据类型的属性,而后者又具有
String
属性
List
自定义数据类型
Set
字符串集合
Array
自定义数据类型数组
Array
字符串数组
Map
字符串和自定义数据类型的映射
对象图:
![enter image description here](https://istack.dev59.com/DEt8a.webp)
测试对象代码片段:
public static Music buildObj() {
Song song1 = new Song();
Song song2 = new Song();
Song song3 = new Song();
Artist artist1 = new Artist();
Artist artist2 = new Artist();
song1.setGenre("ROCK ");
song1.setSonnet("X ");
song1.setNotes("Y ");
song1.setCompostions(Arrays.asList(new String[] { "SOME X DATA ",
"SOME OTHER DATA X ", "SOME MORE DATA X ", " " }));
Set<String> instruments = new HashSet<String>();
instruments.add(" GUITAR ");
instruments.add(" SITAR ");
instruments.add(" DRUMS ");
instruments.add(" BASS ");
song1.setInstruments(instruments);
song2.setGenre("METAL ");
song2.setSonnet("A ");
song2.setNotes("B ");
song2.setCompostions(Arrays.asList(new String[] { "SOME Y DATA ",
" SOME OTHER DATA Y ",
" SOME MORE DATA Y ", " " }));
song3.setGenre("POP ");
song3.setSonnet("DONT ");
song3.setNotes("KNOW ");
song3.setCompostions(Arrays.asList(new String[] { "SOME Z DATA ",
" SOME OTHER DATA Z ",
" SOME MORE DATA Z ", " " }));
artist1.setSongList(Arrays.asList(new Song[] { song1, song3 }));
artist2.setSongList(Arrays.asList(new Song[] { song1, song2, song3 }));
Map<String, Person> artistMap = new HashMap<String, Person>();
Person tutor1 = new Person();
tutor1.setName("JOHN JACKSON DOE ");
artistMap.put(" Name ", tutor1);
Person coach1 = new Person();
coach1.setName("CARTER ");
artistMap.put("Coach ", coach1);
artist2.setTutor(artistMap);
music.setSongs(Arrays.asList(new Song[] { song1, song2, song3 }));
music.setArtists(Arrays.asList(new Artist[] { artist1, artist2 }));
music.setLanguages(new String[] { " ENGLISH ", "FRENCH ",
"HINDI " });
Person singer1 = new Person();
singer1.setName("DAVID ");
Person singer2 = new Person();
singer2.setName("JACOB ");
music.setSingers(new Person[] { singer1, singer2 });
Human man = new Human();
Person p = new Person();
p.setName(" JACK'S RAGING BULL ");
SomeGuy m = new SomeGuy();
m.setPerson(p);
man.setMan(m);
music.setHuman(man);
return music;
}
结果:
#######BEFORE#######
>>[>>DAVID
Number of spaces : 644
#######AFTER#######
>>[>>DAVID
Number of spaces : 111
上述“修剪”输出中空格数量不为零,因为我没有努力覆盖任何集合(List、Set或Map)或Map的toString。我想要对代码进行某些改进,但是对于您的情况,解决方案应该可以正常工作。
限制(进一步的改进):
1. 无法处理属性的不规范语法(无效的getter/setter)。
2. 无法处理链式集合:例如,List> - 因为只支持遵循规范的getter/setter约定。
3. 没有Guava集合库支持。
@Trim
注释的缺点。 - Joop Eggen