i have a maps in java that contains generic value with key string:
String value1 = "value";
Long value2 = 100L;
Map<String, ?> items = new HashMap<>();
items.put("key1", value1);
items.put("key2", value2);
How can I execute a different method
public void customMethod(String str){}
or
public void customMethod(Long lng){}
with foreach map:
items.forEach((key, value) -> customMethod(value))?
thanks
Use reflection to dispatch the call to the appropriate method:
public void customMethod(Object obj) {
try {
getClass().getMethod("customMethod", obj.getClass()).invoke(this, obj);
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
See live demo running with your examples.
However, this implementation is going to be slow because the method must be looked up every time it's used. To make this production ready, you can lookup the method once and cache and re-use it via its MethodHandle:
private static Map<Class<?>, MethodHandle> methodHandleCache = new HashMap<>();
public void customMethod(Object obj) {
try {
methodHandleCache.computeIfAbsent(obj.getClass(), this::findMethodHandle).invoke(this, obj);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
private MethodHandle findMethodHandle(Class<?> clazz) {
try {
MethodType methodType = MethodType.methodType(void.class, clazz);
return MethodHandles.lookup().findVirtual(getClass(), "customMethod", methodType);
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
See live demo.
Related
I'm using the method below to get the names of all getter methods of a class:
private static Map<String, Object> fetchGetterMethods(Object object) {
Map<String, Object> result = new HashMap<String, Object>();
BeanInfo info;
try {
info = Introspector.getBeanInfo(object.getClass());
for (PropertyDescriptor pd : info.getPropertyDescriptors()) {
Method reader = pd.getReadMethod();
if (reader != null) {
String name = pd.getName();
if (!"class".equals(name)) {
try {
Object value = reader.invoke(object);
result.put(name, value);
} catch (Exception e) {
}
}
}
}
} catch (IntrospectionException e) {
} finally {
return result;
}
}
I would like to skip the getter methods annotated with #Transient. How can I implement this?
#Transient
public boolean isValid() {
}
All you need is reader.getAnnotation(Transient.class) - if that returns something (it'll be an instance of Transient), it had the annotation. If it returns null, it did not. You can only do this to annotations whose definition is explicitly annotated with retentionlevel runtime, but assuming you're talking about JPA's #Transient, it is.
Note that writing a return statement in a finally block is absolutely not something you want to do.
You should use the Method#isAnnotationPresent method.
if (!reader.isAnnotationPresent(Transient.class)) {
// do work
}
This is a convenience method for the solution suggested by #rzwitserloot, and is the equivalent to:
if (reader.getAnnotation(Transient.class) == null) {
I have a Java program that calls an external API (RealApi in the code below) and sometimes I want to avoid calling this API and instead return pre-constructed responses (generated by FakeApi).
So, I ended up duplicating this kind of construct in most of my methods:
public Type1 m1(String s) {
try {
Type1 r = FakeApi.m1(s);
if (r != null) {
return r;
}
} catch (Exception e) {
// log error
}
return RealApi.m1(s);
}
What are some options to avoid duplicating this try/catch block everywhere? It's important that if FakeApi throws an exception or returns null, the RealApi must be called.
One option would be encapsulate the error checking behaviour into its own method:
public <T> T fakeOrReal(Supplier<T> fake, Supplier<T> real) {
try {
T r = fake.get();
if (r != null) {
return r;
}
}
catch (Exception e) {
// log error
}
return real.get();
}
You can then just call it with
public Type1 m1(String s) {
return fakeOrReal(() -> FakeApi.m1(s), () -> RealApi.m1(s));
}
This is not as simple as Thomas Preißler's answer but it will help you not repeat any method at all. So if you expand the interface, you have to modify only the concrete classes and not the linker which describes the actual behavior you want.
Create an interface that contains all the methods of RealApi:
interface Api {
Type1 m1(String s);
}
Then a class that does the actual call:
class ConcreteApi implements Api {
public Type1 m1(String s) {
return RealApi.m1(s);
}
}
Then create your FakeApi:
class TotallyFakeApi implements Api {
public Type1 m1(String s) {
return FakeApi.m1(s);
}
}
Now, the tricky part to avoid repeating yourself:
private static Object callImplementation(Api api, Method method, Object[] methodArgs) throws Exception {
Method actualMethod = api.getClass().getMethod(actualMethod.getName(), actualMethod.getParameterTypes());
return actualMethod.invoke(api, methodArgs);
}
Api fakeOrReal(Api fakeApi, Api realApi) {
return (Api) Proxy.newProxyInstance(
FakeApi.class.getClassLoader(),
new Class[]{Api.class},
(proxy, method, methodArgs) -> {
try {
Object r = callImplementation(fakeApi, method, methodArgs);
if (r != null) {
return r;
}
} catch (Exception e) {
// logError(e);
}
return callImplementation(realApi, method, methodArgs);
}
);
}
Get the actual implementation like this:
Api apiToUse = fakeOrReal(new TotallyFakeApi(), new ConcreteApi());
Right now my cache looks like the following:
public class TestCache {
private LoadingCache<String, List<ObjectABC>> cache;
TestCache() {
cache = CacheBuilder.newBuilder().expireAfterAccess(10, TimeUnit.MINUTES).maximumSize(25)
.build(new CacheLoader<String, List<ObjectABC>>(
) {
#Override
public List<ObjectABC> load(String key) throws Exception {
// TODO Auto-generated method stub
return addCache(key);
}
});
}
private List<ObjectABC> addCache(String key) {
final JoiObjectMapper mapper = new JoiObjectMapper();
final Collection<File> allConfigFiles = FileUtils.listFiles(new File(key), null, true);
final List<ObjectABC> configsList = new ArrayList<>();
allConfigFiles.forEach(configFile -> {
try {
configsList.add(mapper.readValue(configFile, new TypeReference<ObjectABC>() {
}));
} catch (Exception e) {
throw new RuntimeException(e);
}
});
return configsList;
}
public List<ObjectABC> getEntry(String key) {
try {
return cache.get(key);
} catch (ExecutionException e) {
throw new NonRetriableException(String.format(
"Exception occured while trying to get data from cache for the key : {} Exception: {}",
key.toString(), e));
}
}
}
In the above code, when I pass a String key (which is path to a local folder) it takes all the files present in that location and maps them to ObjectABC using ObjectMapper.
Now my problem is that I want to instead have a generic loading cache like
LoadingCache<String, List<Object>>.
And I want to map files in different folders to different Objects, e.g. map files in /root/Desktop/folder1 to List<ObjectABC> and map files in /root/Desktop/folder2 to List<ObjectDEF> and be able to store and retrieve that information from the cache.
How can I pass to the cache the information of which object to use for mapping?
You can create a custom class wrapping a LoadingCache<Key<?>, Object> like that:
class HeterogeneousCache {
private final LoadingCache<Key<?>, Object> cache;
public <T> T get(Key<T> key) throws ExecutionException {
return key.getType().cast(cache.get(key));
}
}
#Value // provides constructor, getters, equals, hashCode
class Key<T> {
private final String identifier;
private final Class<T> type;
}
(I used Lombok's #Value annotation for simplicity)
Of course, this is just a stub and you might need to adapt this to your needs. The main problem might be that you can't get a Class<List<ObjectABC>> - you can only get a Class<List>. The easiest way out of this is to wrap the List<ObjectABC> in some custom type. The harder way (not recommended) is to use Guava's TypeToken.
Attribution: This answer is based on the post by Frank Appel entitled How to Map Distinct Value Types Using Java Generics, which itself is based on Joshua Bloch's typesafe hetereogeneous containers from Effective Java.
Edit: A Complete Solution
Since the OP wants List<T> as result, and since he needs instances of TypeReference<T>, I replaced Class<T> with TypeReference<T> in Key<T>:
#Value // provides constructor, getters, equals, hashCode
class Key<T> {
private final String identifier;
private final TypeReference<T> typeReference;
}
Here's how CustomHeterogeneousCache looks now:
class CustomHeterogeneousCache {
private final LoadingCache<Key<?>, List<?>> cache = CacheBuilder.newBuilder()
.expireAfterAccess(10, TimeUnit.MINUTES)
.maximumSize(25)
.build(CacheLoader.from(this::computeEntry));
#SuppressWarnings("unchecked")
public <T> List<T> getEntry(Key<T> key) {
return (List<T>) cache.getUnchecked(key);
}
private <T> List<T> computeEntry(Key<T> key) {
final JoiObjectMapper mapper = new JoiObjectMapper();
final Collection<File> allConfigFiles = FileUtils.listFiles(new File(key.getIdentifier()), null, true);
return allConfigFiles.stream()
.map(configFile -> {
try {
return mapper.readValue(configFile, key.getTypeReference());
} catch (Exception e) {
throw new RuntimeException(e);
}
})
.collect(Collectors.toList());
}
}
Since implementations of TypeReference do not have value semantics, the user must make sure that every Key is created once, and then only referenced, e.g.:
class Keys {
public static final Key<ObjectABC> ABC = new Key<>("/root/Desktop/folder1", new TypeReference<ObjectABC>() {
});
public static final Key<ObjectDEF> DEF = new Key<>("/root/Desktop/folder2", new TypeReference<ObjectDEF>() {
});
}
I'm working on legacy project and I've trapped into situation when I have to make additional init stuff with action object. In this code AdmAction is a basic interface and inside method I could have any of it's implementation. Some of implementations require additional properties must be initialized with values from utilParams.
private void initActionParams(AdmAction action, Map<String, Object> utilParams) {
if (utilParams == null) {
return;
}
utilParams.forEach((paramName, value) -> {
try {
Method setterMethod = action.getClass().getMethod(setterFor(paramName), value.getClass());
setterMethod.invoke(action, value);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
log.error(e.getMessage(), e);
throw new WebApplicationException(e, Response.Status.BAD_REQUEST);
}
});
}
utilParams looks like "serviceId": 10 of "ticketId": "8a30f5a7-809c-4551-8833-c2a60e4c6fd9".
Code works fine when value is an Object type (String, Integer etc.) and when setter method of AdmAction implementation consumes the same.
But there's one problem when I've got for example Integer type in utilParams and setter method in action which consumes int.
Of course code throws NoSuchMethodException
Example:
Action impl:
public class Foo implements AdmAction {
// ...
public void setServiceId(int serviceId) {
this.serviceId = serviceId;
}
}
Causes an exception.
I've tried to improve code with method search:
private void initActionParams(AdmAction action, Map<String, Object> utilParams) {
if (utilParams == null) {
return;
}
utilParams.forEach((paramName, value) -> {
try {
Method setterMethod = Arrays.stream(action.getClass().getDeclaredMethods())
.filter((Method method) -> method.getName().equals(setterFor(paramName)))
.findFirst()
.orElseThrow(NoSuchMethodException::new);
setterMethod.invoke(action, value);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
log.error(e.getMessage(), e);
throw new WebApplicationException(e, Response.Status.BAD_REQUEST);
}
});
I guess it's a little bit brute for actual case.
Can anybody help me find the way to write better and more aesthetic code?
You could use java.beans.Statement for this, which will do unboxing.
java.beans.Statement(action, setterFor(paramName), new Object[] {value})
.execute();
I'm trying to understand new functions of java8: forEach and lambda expressions.
Trying to rewrite this function:
public <T extends Object> T copyValues(Class<T> type, T source, T result)
throws IllegalAccessException
{
for(Field field : getListOfFields(type)){
field.set(result, field.get(source));
}
return result;
}
using lambda.
I think it should be something like this but can't make it right:
() -> {
return getListOfFields(type).forEach((Field field) -> {
field.set(result, field.get(source));
});
};
The loop can be replaced by
getListOfFields(type).forEach((field) -> field.set(result, field.get(source)));
However, that forEach method call has no return value, so you still need to
return result;
separately.
The full method:
public <T extends Object> T copyValues(Class<T> type, T source, T result)
throws IllegalAccessException
{
getListOfFields(type).forEach((field) -> field.set(result, field.get(source)));
return result;
}
EDIT, I didn't notice the issue with the exception. You'll have to catch the exception and throw some unchecked exception. For example:
public <T extends Object> T copyValues(Class<T> type, T source, T result)
{
getListOfFields(type).forEach (
(field) -> {
try {
field.set(result, field.get(source));
} catch (IllegalAccessException ex) {
throw new RuntimeException (ex);
}
});
return result;
}
You could use functions in the following way:
#FunctionalInterface
interface CopyFunction<T> {
T apply(T source, T result) throws Exception;
}
public static <T> CopyFunction<T> createCopyFunction(Class<T> type) {
return (source, result) -> {
for (Field field : getListOfFields(type)) {
field.set(result, field.get(source));
}
return result;
};
}
And then:
A a1 = new A(1, "one");
A a2 = new A(2, "two");
A result = createCopyFunction(A.class).apply(a1, a2);
The CopyFunction functional interface is pretty much the same as BinaryOperator except that BinaryOperator doesn't throw an exception. If you want to handle exceptions within a function, you can use the BinaryOperator instead.