Java 8, чтобы удалить строковое значение из каждого поля, в котором значение "string" происходит из пользовательского объекта - PullRequest
0 голосов
/ 04 апреля 2020

Я перешел по ссылке: Можно ли в Java проверить, являются ли поля объектов пустыми, а затем добавить значение по умолчанию для всех этих атрибутов? и реализовать то же решение, что и ниже -

Примечание: я использую Swagger / Open API Specs (используя springdo c -openapi-ui) и при выполнении POST запрашиваем все строковые поля имея значение по умолчанию как «строку», которую я действительно хотел установить в ноль или пробел.

Какой-нибудь быстрый указатель?

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

@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 Ответ

0 голосов
/ 04 апреля 2020

Думаю, вы могли бы сделать это немного проще. Если вы управляете EmployeeDto, например:

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

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

}

Вы можете перебирать поля класса и, используя MethodHandles, вызывать необходимые сеттеры, когда некоторые геттеры возвращают интересующий вас string ( и строки сравниваются с использованием equals, а не ==). Это даже можно превратить в крошечную библиотеку. Вот начало:

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);
                         }
                     }
                 ));
}

С этой информацией вы можете предоставить публикуемый c метод для вызова пользователями, поэтому вам нужно предоставить фактический экземпляр вашего DTO, класса DTO, Class of поля, для которых вы хотите задать «значение по умолчанию», равенство для проверки и фактическое значение 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;

}

И вот как ваши абоненты могут назвать его:

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);
}
...