Skip to content

Commit e14bff2

Browse files
committed
Add reflection utils
1 parent edc53d8 commit e14bff2

2 files changed

Lines changed: 196 additions & 0 deletions

File tree

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Copyright 2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.appulse.utils;
18+
19+
import static java.util.Optional.empty;
20+
import static java.util.Optional.ofNullable;
21+
22+
import java.security.AccessController;
23+
import java.security.PrivilegedAction;
24+
import java.util.Optional;
25+
import java.util.function.Function;
26+
import java.util.function.Predicate;
27+
import java.util.stream.Stream;
28+
29+
import lombok.NonNull;
30+
import lombok.SneakyThrows;
31+
import lombok.val;
32+
33+
/**
34+
* Different reflection helpers.
35+
*
36+
* @author Artem Labazin
37+
* @since 1.0.1
38+
*/
39+
public final class ReflectionUtils {
40+
41+
/**
42+
* Extracts field value from object by its name.
43+
*
44+
* @param obj object, from which need to extract field's value.
45+
* @param name field's name
46+
*
47+
* @return optional - field's value or nothing.
48+
*/
49+
@SneakyThrows
50+
public static Optional<Object> getFieldValueFrom (@NonNull Object obj, @NonNull String name) {
51+
val optional = findIn(obj, Class::getDeclaredFields, field -> field.getName().equals(name));
52+
if (optional.isPresent()) {
53+
val field = optional.get();
54+
AccessController.doPrivileged(new PrivilegedAction<Object>() {
55+
56+
@Override
57+
public Object run () {
58+
field.setAccessible(true);
59+
return null;
60+
}
61+
});
62+
val value = field.get(obj);
63+
return ofNullable(value);
64+
}
65+
return empty();
66+
}
67+
68+
/**
69+
* Invoke method of object with specified arguments.
70+
*
71+
* @param obj object
72+
* @param name method's name
73+
* @param arguments optional arguments for method
74+
*
75+
* @return method's invocation result.
76+
*/
77+
@SneakyThrows
78+
public static Object invokeMethodOf (@NonNull Object obj, @NonNull String name, Object... arguments) {
79+
val optional = findIn(obj, Class::getDeclaredMethods, method -> method.getName().equals(name));
80+
if (optional.isPresent()) {
81+
val method = optional.get();
82+
return method.invoke(obj, arguments);
83+
}
84+
return null;
85+
}
86+
87+
// Searches method/field in object by predicate.
88+
private static <T> Optional<T> findIn (Object obj, Function<Class<?>, T[]> extractor, Predicate<T> predicate) {
89+
Class<?> current = obj.getClass();
90+
91+
while (current != null) {
92+
val values = extractor.apply(current);
93+
val optional = Stream.of(values)
94+
.filter(predicate)
95+
.findFirst();
96+
97+
if (optional.isPresent()) {
98+
return optional;
99+
}
100+
current = current.getSuperclass();
101+
}
102+
return empty();
103+
}
104+
105+
private ReflectionUtils () {
106+
}
107+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Copyright 2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.appulse.utils;
18+
19+
import static org.assertj.core.api.Assertions.assertThat;
20+
21+
import lombok.Getter;
22+
import lombok.RequiredArgsConstructor;
23+
import lombok.Setter;
24+
import org.junit.Test;
25+
26+
/**
27+
*
28+
* @author Artem Labazin
29+
*/
30+
public class ReflectionUtilsTest {
31+
32+
@Test
33+
public void getFieldValueFrom () {
34+
ChildClass object = new ChildClass("Artem", 27);
35+
36+
assertThat(ReflectionUtils.getFieldValueFrom(object, "name"))
37+
.isPresent()
38+
.hasValue("Artem");
39+
40+
assertThat(ReflectionUtils.getFieldValueFrom(object, "age"))
41+
.isPresent()
42+
.hasValue(27);
43+
44+
assertThat(ReflectionUtils.getFieldValueFrom(object, "popa"))
45+
.isNotPresent();
46+
}
47+
48+
@Test
49+
public void invokeMethodOf () {
50+
ChildClass object = new ChildClass("Artem", 27);
51+
52+
assertThat(ReflectionUtils.invokeMethodOf(object, "getName"))
53+
.isNotNull()
54+
.isEqualTo("Artem");
55+
56+
assertThat(ReflectionUtils.invokeMethodOf(object, "getAge"))
57+
.isNotNull()
58+
.isEqualTo(27);
59+
60+
assertThat(object.isFlag()).isFalse();
61+
assertThat(ReflectionUtils.invokeMethodOf(object, "setFlag", true))
62+
.isNull();
63+
assertThat(object.isFlag()).isTrue();
64+
65+
assertThat(ReflectionUtils.invokeMethodOf(object, "popa"))
66+
.isNull();
67+
}
68+
69+
@Getter
70+
@RequiredArgsConstructor
71+
class ParentClass {
72+
73+
private final int age;
74+
}
75+
76+
@Getter
77+
class ChildClass extends ParentClass {
78+
79+
private final String name;
80+
81+
@Setter
82+
private boolean flag;
83+
84+
ChildClass (String name, int age) {
85+
super(age);
86+
this.name = name;
87+
}
88+
}
89+
}

0 commit comments

Comments
 (0)