Java 8 to remove string value from each field where “string” value comes of the Custom Object

杀马特。学长 韩版系。学妹 提交于 2020-04-12 07:25:29

问题


I went through link: Is it possible in Java to check if objects fields are null and then add default value to all those attributes? and implemented the same solution as below -

Note: I am using Swagger/Open API Specs (using springdoc-openapi-ui) and while making POST request all string fields are having default value as "string" which I really wanted to set it to null or space.

Any quick pointer ?

public static Object getObject(Object obj) {
        for (Field f : obj.getClass().getFields()) {
            f.setAccessible(true);
            try {
                if (f.get(obj) == "string") {
                    f.set(obj, null);
                }
            } catch (IllegalArgumentException | IllegalAccessException e) {
                log.error("Error While Setting default values for String");
            }
        }
   return obj;
}

REST endpoints

@GetMapping(value = "/employees")
public ResponseEntity<PagedModel<EmployeeModel>> findEmployees(
        EmployeeDto geoDto,
        @Parameter(hidden=true) String sort,
        @Parameter(hidden=true) String order,
        @Parameter(hidden=true) Pageable pageRequest) {

    EmployeeDto dto = (EmployeeDto) CommonsUtil.getObject(geoDto);

    Page<CountryOut> response = countryService..............;
    PagedModel<EmployeeModel> model = employeePagedAssembler.toModel(response, countryOutAssembler);

    return new ResponseEntity<>(model, HttpStatus.OK);
}

回答1:


You could do it a bit simpler, I guess. If you control EmployeeDto, for example:

@Accessors(chain = true)
@Getter
@Setter
@ToString
static class EmployeeDto {

    private String firstname;
    private String lastname;
    private int age;

}

You could iterate over fields of the class and using MethodHandles invoke the needed setters, when some getters return the string you are interested in (and Strings are compared using equals, not ==). This can even be made into a tiny library. Here is a start:

private static final Lookup LOOKUP = MethodHandles.lookup();

/**
 * this computes all the know fields of some class (EmployeeDTO in your case) and their getter/setter
 */
private static final Map<Class<?>, Map<Entry<String, ? extends Class<?>>, Entry<MethodHandle, MethodHandle>>> ALL_KNOWN =
    Map.of(
        EmployeeDto.class, metadata(EmployeeDto.class)
    );
private Map<String, Entry<MethodHandle, MethodHandle>> MAP;

/**
 * For example this will hold : {"firstname", String.class} -> getter/setter to "firstname"
 */
private static Map<Entry<String, ? extends Class<?>>, Entry<MethodHandle, MethodHandle>> metadata(Class<?> cls) {
    return Arrays.stream(cls.getDeclaredFields())
                 .map(x -> new SimpleEntry<>(x.getName(), x.getType()))
                 .collect(Collectors.toMap(
                     Function.identity(),
                     entry -> {
                         try {
                             return new SimpleEntry<>(
                                 LOOKUP.findGetter(cls, entry.getKey(), entry.getValue()),
                                 LOOKUP.findSetter(cls, entry.getKey(), entry.getValue()));
                         } catch (Throwable t) {
                             throw new RuntimeException(t);
                         }
                     }
                 ));
}

With that information you can provide a public method for users to call, So you need to provide the actual instance of your DTO, the DTO class, the Class of the fields you want to "default to", the equality to check against and the actual defaultValue.

    public static <T, R> T defaulter(T initial,
                                  Class<T> dtoClass,
                                  Class<R> fieldType,
                                  R equality,
                                  R defaultValue) throws Throwable {

    Set<Entry<MethodHandle, MethodHandle>> all =
        ALL_KNOWN.get(dtoClass)
                 .entrySet()
                 .stream()
                 .filter(x -> x.getKey().getValue() == fieldType)
                 .map(Entry::getValue)
                 .collect(Collectors.toSet());

    for (Entry<MethodHandle, MethodHandle> getterAndSetter : all) {
        R whatWeGot = (R) getterAndSetter.getKey().invoke(initial);
        if (Objects.equals(whatWeGot, equality)) {
            getterAndSetter.getValue().invoke(initial, defaultValue);
        }
    }

    return initial;

}

And this is how your callers can call it:

public static void main(String[] args) throws Throwable {
    EmployeeDto employeeDto = new EmployeeDto()
        .setFirstname("string")
        .setLastname("string");

    EmployeeDto withDefaults = defaulter(employeeDto, EmployeeDto.class, String.class, "string", "defaultValue");

    System.out.println(withDefaults);
}


来源:https://stackoverflow.com/questions/61032842/java-8-to-remove-string-value-from-each-field-where-string-value-comes-of-the

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!