Java 8将从自定义对象的每个字段中删除“string”值。

huangapple go评论81阅读模式
英文:

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

问题

我浏览了链接https://stackoverflow.com/questions/2146129/is-it-possible-in-java-to-check-if-objects-fields-are-null-and-then-add-default 并实施了以下相同的解决方案 -

注意我正在使用 **Swagger/Open API规范使用springdoc-openapi-ui**在进行 ***POST*** 请求时所有字符串字段的默认值都为"string"而我真的希望将其设置为null或空白

有什么快速的指针吗

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);
}
英文:

I went through link: https://stackoverflow.com/questions/2146129/is-it-possible-in-java-to-check-if-objects-fields-are-null-and-then-add-default 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

得分: 0

你可以简化一下,我猜。如果你控制EmployeeDto,例如:

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

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

}

你可以迭代类的字段,并使用MethodHandles调用需要的setter,当一些getter返回你感兴趣的string(并且字符串使用equals而不是==进行比较)。这甚至可以制作成一个小型库。这是一个开始:

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

/**
 * 这计算了一些类(在你的情况下是EmployeeDTO)的所有已知字段及其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;

/**
 * 例如,这将保存:{"firstname",String.class} -> getter/setter 到 "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);
                         }
                     }
                 ));
}

有了这些信息,您可以为用户提供一个公共方法来调用,因此您需要提供DTO的实际实例,DTO类,要“默认为”的字段的Class,要检查的相等性以及实际的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);
}
英文:

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&lt;Class&lt;?&gt;, Map&lt;Entry&lt;String, ? extends Class&lt;?&gt;&gt;, Entry&lt;MethodHandle, MethodHandle&gt;&gt;&gt; ALL_KNOWN =
Map.of(
EmployeeDto.class, metadata(EmployeeDto.class)
);
private Map&lt;String, Entry&lt;MethodHandle, MethodHandle&gt;&gt; MAP;
/**
* For example this will hold : {&quot;firstname&quot;, String.class} -&gt; getter/setter to &quot;firstname&quot;
*/
private static Map&lt;Entry&lt;String, ? extends Class&lt;?&gt;&gt;, Entry&lt;MethodHandle, MethodHandle&gt;&gt; metadata(Class&lt;?&gt; cls) {
return Arrays.stream(cls.getDeclaredFields())
.map(x -&gt; new SimpleEntry&lt;&gt;(x.getName(), x.getType()))
.collect(Collectors.toMap(
Function.identity(),
entry -&gt; {
try {
return new SimpleEntry&lt;&gt;(
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 &lt;T, R&gt; T defaulter(T initial,
Class&lt;T&gt; dtoClass,
Class&lt;R&gt; fieldType,
R equality,
R defaultValue) throws Throwable {
Set&lt;Entry&lt;MethodHandle, MethodHandle&gt;&gt; all =
ALL_KNOWN.get(dtoClass)
.entrySet()
.stream()
.filter(x -&gt; x.getKey().getValue() == fieldType)
.map(Entry::getValue)
.collect(Collectors.toSet());
for (Entry&lt;MethodHandle, MethodHandle&gt; 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(&quot;string&quot;)
.setLastname(&quot;string&quot;);
EmployeeDto withDefaults = defaulter(employeeDto, EmployeeDto.class, String.class, &quot;string&quot;, &quot;defaultValue&quot;);
System.out.println(withDefaults);
}

huangapple
  • 本文由 发表于 2020年4月5日 02:27:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/61032842.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定