Edit: after you have added the most important piece of information in the comment "what if someone changes that name in the future"... well... then reflection is not the way to go!
I would then rather use something like a Function<RequestDto, String>
or similar instead, e.g.:
static String getCustom(RequestDto requestDto, Function<RequestDto, String> customExtractor) {
return customExtractor.apply(requestDto);
}
and call it via:
RequestDto someRequest = ...;
getCustom(someRequest, RequestDto::getCustom);
If that field is refactored in future that part will be refactored too then automatically (well... depends on your IDE probably ;-)). But... it will not give you the appropriate field name as error message. Note that there isn't a nice way to catch the right field, if the only property to get it, is its name. If you would put an annotation to the field, you could then filter and grab the field with that specific annotation. That way you do not need to know the actual name... but counterquestion: how can you be sure that only 1 field is annoted with that annotation? I would rather redesign that specific part of your application. I wouldn't expose any field to the "client". If that means that I have potentially different names in the error message and the field names, so be it.
Note also that modern IDEs allow you to refactor strings as well (when you rename a field). You just need to ensure that this information is spread across the team then (and also future members).
Previous answer using reflection:
If with dynamic you mean, that it must start with that name or contain that name, you may want to use something as follows, i.e. getDeclaredFields()
and iterate over them to filter out interested fields:
private static String getCustom(RequestDto requestDto) throws NoSuchFieldException, IllegalAccessException {
return Arrays.stream(requestDto.getClass().getDeclaredFields())
.filter(e -> e.getName().startsWith("custom"))
.findFirst() // if the first match suffices
.map(f -> { // you may want to extract that part if you use streams
f.setAccessible(true);
try {
return (String) f.get(requestDto);
} catch (IllegalAccessException e) {
// TODO whatever you need to do...
return null;
}
}).orElseThrow(IllegalArgumentException::new); // or whatever suites better
}
This sample should suffice in case you need to filter by type or by annotation, etc. Just adapt the filter then accordingly.
If it's just the name of a field that you require, it is Field.getName()
what you want.