是否有一个常见的Java方法来修剪对象图中的每个字符串?

Pet*_*ith 6 java string reflection object-graph

我希望修剪作为对象图的一部分的所有字符串.

所以我有一个像这样的对象图

 RootElement
   - name (String)
   - adjective (String)
   - items ArrayOfItems
     - getItems (List<Item>)
       - get(i) (Item)
       Item
         - name (String)
         - value (double)
         - alias (String)
         - references ArrayOfReferences
           - getReferences (List<Reference>)
             - get(i) (Reference)
             Reference
               - prop1 (String)
               - prop2 (Integer)
               - prop3 (String)
Run Code Online (Sandbox Code Playgroud)

对象图中表示的每个类的每个属性都有一个get和set对.理想情况下,String类型的每个字段都会被修剪,包括枚举集合中包含的任何子对象.对象图中没有包含循环.

是否有任何java库实现某种通用对象图访问者模式或String\Reflection实用程序库来执行此操作?

执行此操作的外部第三方库也可以,它不必是标准Java库的一部分.

chr*_*ke- 10

不,没有内置遍历这样的东西,并记住Java String是不可变的,所以你不能实际修剪到位 - 你必须修剪和替换.某些对象可能不允许修改其String变量.


Pop*_*ibo 5

以下是我使用Java Reflection API构建的解决方案的说明.我在下面发布了工作代码(及其url到github).该解决方案主要用于:

  1. Java Reflection API
  2. 独立处理 Java Collections
  3. 递归

首先,我用Introspector走了过来readMethodsClass省略了定义的方法Object

for (PropertyDescriptor propertyDescriptor : Introspector
                    .getBeanInfo(c, Object.class).getPropertyDescriptors()) {
            Method method = propertyDescriptor.getReadMethod();
Run Code Online (Sandbox Code Playgroud)

案例

  1. 如果当前级别Property是类型String
  2. 如果是一个Object属性数组
  3. 如果它是一个String数组
  4. 如果是一种Java Collection
  5. Map具有特殊条件的单独放置以处理其keysvalues

该实用程序用于Java Reflection API遍历具有规律性语法的对象图,getters并且以递归方式setters修剪图中Strings遇到的所有内容Object.

这个包含主要测试类(以及自定义数据类型/ pojos)的整个util类都在我的github上

用法:

myObj = (MyObject) SpaceUtil.trimReflective(myObj);
Run Code Online (Sandbox Code Playgroud)

Util方法:

    public static Object trimReflective(Object object) throws Exception {
        if (object == null)
            return null;

        Class<? extends Object> c = object.getClass();
        try {
            // Introspector usage to pick the getters conveniently thereby
            // excluding the Object getters
            for (PropertyDescriptor propertyDescriptor : Introspector
                    .getBeanInfo(c, Object.class).getPropertyDescriptors()) {
                Method method = propertyDescriptor.getReadMethod();
                String name = method.getName();

                // If the current level of Property is of type String
                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 to trim and set the trimmed String value
                            setter.invoke(object, property.trim());
                    }
                }

                // If an Object Array of Properties - added additional check to
                // avoid getBytes returning a byte[] and process
                if (method.getReturnType().isArray()
                        && !method.getReturnType().isPrimitive()
                        && !method.getReturnType().equals(String[].class)
                        && !method.getReturnType().equals(byte[].class)) {
                    System.out.println(method.getReturnType());
                    // Type check for primitive arrays (would fail typecasting
                    // in case of int[], char[] etc)
                    if (method.invoke(object) instanceof Object[]) {
                        Object[] objectArray = (Object[]) method.invoke(object);
                        if (objectArray != null) {
                            for (Object obj : (Object[]) objectArray) {
                                // Recursively revisit with the current property
                                trimReflective(obj);
                            }
                        }
                    }
                }
                // If a String array
                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();

                            // Explicit wrapping
                            setter.invoke(object,
                                    new Object[] { modifiedArray });
                        }
                    }
                }
                // Collections start
                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) {
                                    // Check if List was created with
                                    // Arrays.asList (non-resizable Array)
                                    if (collectionProperty instanceof List) {
                                        ((List) collectionProperty).set(index,
                                                element.trim());
                                    } else {
                                        collectionProperty.remove(element);
                                        collectionProperty.add(element.trim());
                                    }
                                }
                            } else {
                                // Recursively revisit with the current property
                                trimReflective(collectionProperty.toArray()[index]);
                            }
                        }
                    }
                }
                // Separate placement for Map with special conditions to process
                // keys and values
                if (method.getReturnType().equals(Map.class)) {
                    Map mapProperty = (Map) method.invoke(object);
                    if (mapProperty != null) {
                        // Keys
                        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 {
                                // Recursively revisit with the current property
                                trimReflective(mapProperty.get(index));
                            }

                        }
                        // Values
                        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 {
                                // Recursively revisit with the current property
                                trimReflective(entry.getValue());
                            }
                        }
                    }
                } else {// Catch a custom data type as property and send through
                        // recursion
                    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;

    }
Run Code Online (Sandbox Code Playgroud)

测试

我还有一个测试类,它创建了一个相对复杂的对象.测试类有不同的场景,包括:

  1. String 性能
  2. 属性作为自定义数据类型,而后者又具有String属性
  3. 属性作为自定义数据类型,而自定义数据类型又将属性作为自定义数据类型,而自定义数据类型又具有String属性
  4. List 自定义数据类型
  5. SetStrings
  6. Array 自定义数据类型
  7. ArrayStrings
  8. MapString和自定义数据类型

对象图:

在此输入图像描述

测试对象代码片段:

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;
}
Run Code Online (Sandbox Code Playgroud)

结果:

#######BEFORE#######
>>[>>DAVID      ---<<, >>JACOB      ---<<]---[    ENGLISH    , FRENCH    , HINDI    ]---[>>ROCK       ---X    ---Y    ---[SOME X DATA  , SOME OTHER DATA X , SOME MORE DATA X    ,  ]---[         SITAR    ,          GUITAR    ,          BASS    ,          DRUMS    ]<<, >>METAL       ---A    ---B    ---[SOME Y DATA  ,           SOME OTHER DATA Y ,            SOME MORE DATA Y    ,  ]---<<, >>POP       ---DONT    ---KNOW     ---[SOME Z DATA  ,                SOME OTHER DATA Z ,           SOME MORE DATA Z   ,  ]---<<]---[>>---[>>ROCK       ---X    ---Y    ---[SOME X DATA  , SOME OTHER DATA X , SOME MORE DATA X    ,  ]---[         SITAR    ,          GUITAR    ,          BASS    ,          DRUMS    ]<<, >>POP       ---DONT    ---KNOW     ---[SOME Z DATA  ,                SOME OTHER DATA Z ,           SOME MORE DATA Z   ,  ]---<<]<<, >>{Coach      =>>CARTER    ---<<,           Name                 =>>JOHN JACKSON DOE       ---<<}---[>>ROCK       ---X    ---Y    ---[SOME X DATA  , SOME OTHER DATA X , SOME MORE DATA X    ,  ]---[         SITAR    ,          GUITAR    ,          BASS    ,          DRUMS    ]<<, >>METAL       ---A    ---B    ---[SOME Y DATA  ,           SOME OTHER DATA Y ,            SOME MORE DATA Y    ,  ]---<<, >>POP       ---DONT    ---KNOW     ---[SOME Z DATA  ,                SOME OTHER DATA Z ,           SOME MORE DATA Z   ,  ]---<<]<<]---=>   JACK'S RAGING BULL   <=<<
Number of spaces : 644
#######AFTER#######
>>[>>DAVID---<<, >>JACOB---<<]---[ENGLISH, FRENCH, HINDI]---[>>ROCK---X---Y---[SOME X DATA, SOME OTHER DATA X, SOME MORE DATA X, ]---[GUITAR, SITAR, DRUMS, BASS]<<, >>METAL---A---B---[SOME Y DATA, SOME OTHER DATA Y, SOME MORE DATA Y, ]---<<, >>POP---DONT---KNOW---[SOME Z DATA, SOME OTHER DATA Z, SOME MORE DATA Z, ]---<<]---[>>---[>>ROCK---X---Y---[SOME X DATA, SOME OTHER DATA X, SOME MORE DATA X, ]---[GUITAR, SITAR, DRUMS, BASS]<<, >>POP---DONT---KNOW---[SOME Z DATA, SOME OTHER DATA Z, SOME MORE DATA Z, ]---<<]<<, >>{Name=>>JOHN JACKSON DOE---<<, Coach=>>CARTER---<<}---[>>ROCK---X---Y---[SOME X DATA, SOME OTHER DATA X, SOME MORE DATA X, ]---[GUITAR, SITAR, DRUMS, BASS]<<, >>METAL---A---B---[SOME Y DATA, SOME OTHER DATA Y, SOME MORE DATA Y, ]---<<, >>POP---DONT---KNOW---[SOME Z DATA, SOME OTHER DATA Z, SOME MORE DATA Z, ]---<<]<<]---=>JACK'S RAGING BULL<=<<
Number of spaces : 111
Run Code Online (Sandbox Code Playgroud)

上面的trimmed输出中有一个非零的空格数,因为我没有努力覆盖toString任何集合(List,Set)或Map.我想要的代码有一些改进,但对于你的情况,解决方案应该工作得很好.

限制(进一步改进)

  1. 无法处理属性的无纪律语法(无效的getter/setter)
  2. 无法处理链式集合:例如,List<List<Person>>- 因为对纪律严明的getter/setter约定的独占支持
  3. 没有Guava集合库支持