It is difficult to find any clues for the topic. All I could find is questions about converting one functional interface to another and some articles on type casting in Java. Not what I was looking for.
This question is about converting lambda → Method and I want the opposite, to convert Method to any functional interface, for example, to Consumer.
The way I found is to create a lambda adapter around the Method#invoke method:
public void registerCallbacks(final Object annotated) {
Class clazz = annotated.getClass();
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(Callback.class)) {
Callback registration = method.getAnnotation(Callback.class);
List<String> warnings = new ArrayList<>(3);
if (!Modifier.isPublic(method.getModifiers()))
warnings.add(String.format("Method %s must be public", method));
if (method.getParameterCount() != 1)
warnings.add(String.format("Method %s must consume only one argument", method));
if (method.getParameterCount() == 1 && !method.getParameterTypes()[0].equals(Integer.class))
warnings.add(String.format("Method %s must consume %s", method, Integer.class));
if (!warnings.isEmpty()) {
warnings.forEach(log::warn);
continue;
}
CALLBACKS_MAPPER.registerCallback((param) -> {
try {
method.invoke(annotated, param);
} catch (IllegalAccessException | InvocationTargetException e) {
// Should not happen due to checks before.
log.warn(String.format("Could not invoke %s on %s with %s", method, annotated, param), e);
}
});
log.info("Registered {} as a callback", method);
}
}
}
However I want to avoid writing
CALLBACKS_MAPPER.registerCallback((param) -> {
try {
method.invoke(annotated, param);
} catch (IllegalAccessException | InvocationTargetException e) {
// Should not happen due to checks before.
log.warn(String.format("Could not invoke %s on %s with %s", method, annotated, param), e);
}
});
in favor of something simpler, like
CALLBACKS_MAPPER.registerCallback(SomeApacheLib.methodToFunction(annotated, method));
➥ So, is there a way to map old Java 1.1 reflection library to newer Java 8 functional interfaces, or it is me being stupid and the abovementioned solution with lambda is fine as it is?
If you're content with using reflection under the hood, just don't like the try/catch around the invoke, you can just make a simple utility function like:
public static <T> Consumer<T> toConsumer(Object annotated, Method m) {
return param -> {
try {
m.invoke(annotated, param);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
};
}
And that gives you exactly the syntax you wanted:
CALLBACKS_MAPPER.registerCallback(toConsumer(annotated, method));
But if you want to actually avoid reflection altogether, you can use LambdaMetafactory to create a Consumer:
static Consumer<String> toConsumer(MethodHandles.Lookup lookup, Object annotated, Method method) throws Throwable {
MethodType consumeString = MethodType.methodType(void.class, String.class);
MethodHandle handle = lookup.unreflect(method);
final CallSite site = LambdaMetafactory.metafactory(lookup, "accept",
MethodType.methodType(Consumer.class, annotated.getClass()),
consumeString.changeParameterType(0, Object.class),
handle,
consumeString);
return (Consumer<String>) site.getTarget().invoke(annotated);
}
Change String to whatever your callbacks are expected to accept. And then:
CALLBACKS_MAPPER.registerCallback(toConsumer(MethodHandles.lookup(), annotated, method));
Of course, the only proper solution here is that you refactor your code to use a known callback interface on which you can normally call a defined method, instead of passing Methods around.
Related
im currently working in a complete generic scenario in which i map a json as string to a dto class. That works fine with my function mapJsonToDto but im trying to make it more generic so that the developer who uses this function can also specify what exception to be thrown. So they can catch as they like. With this i avoid catching an IOException. Letting the function handle everything.
public class MapperUtils {
public <T extends Throwable> Object mapJsonToDto(Class<?> dtoClass, String jsonDto, T exceptionToThrow) throws IOException {
Object dto = null;
try {
dto = new ObjectMapper().readValue(jsonDto, dtoClass);
} catch (IOException e) {
throw new exceptionToThrow();
}
return dto;
}
}
I cannot understand how to pass an exception class instance to a function and throwing that specific as well.
Instead of passing the exception to throw (which would then have a completely wrong stack trace), I think you'd want a function that converts an exception from one type to another:
public <T extends Throwable, D> D mapJsonToDto(Class<D> dtoClass, String json, Function<IOException, T> exceptionMapper) throws T {
try {
return new ObjectMapper().readValue(json, dtoClass);
// if readValue doesn't do the casting right, try:
return dtoClass.cast(new ObjectMapper().readValue(json, dtoClass);
} catch (IOException e) {
throw exceptionMapper.apply(e);
}
}
And an example:
Person p = mapJsonToDto(Person.class, "{name: \"Joe\"}",
e -> new IllegalArgumentException("malformed JSON", e));
As a general rule, though, this seems like boneheaded design. If you find the IOException overly general, then you can't handwave the problem away by allowing the caller to provide a no doubt similarly overly general mapper. The only way out for a caller is to do a deep dive on the exception and write, I dunno, an if/elseif block with a ton of levels to it to try to ascertain the real problem e.g. via analysing the message, which is all sorts of ugly.
Either you don't care about that level of detail and you should therefore just stick with IOException (what point is there adding code and pointless layers of indirection?), or you do care and this isn't good enough; you'd want to design a better error system. Except, that's not your job, that'd be ObjectMapper.readValue's job. Which is why the IOException it throws should probably just be sent on unmolested.
Your example is nearly done.
I changed only the throws Type to T and throw the given exception.
public <T extends Throwable> Object mapJsonToDto(Class<?> dtoClass, String jsonDto, T exceptionToThrow) throws T {
Object dto = null;
try {
dto = new ObjectMapper().readValue(jsonDto, dtoClass);
} catch (IOException e) {
throw exceptionToThrow;
}
return dto;
}
Call: mapJsonToDto(String.class, "helo", new IllegalStateException());
I have defined a function in Kotlin:
fun convertExceptionToEmpty(requestFunc: () -> List<Widget>): Stream<Widget> {
try {
return requestFunc().stream()
} catch (th: Throwable) {
// Log the exception...
return Stream.empty()
}
}
I have defined a Java method with this signature:
List<Widget> getStaticWidgets() throws IOException;
I attempt to compose them like so:
Stream<Widget> widgets = convertExceptionToEmpty(() -> getStaticWidgets())
When I compile I get this error:
Error:(ln, col) java: unreported exception java.io.IOException; must be caught or declared to be thrown
How do I define my function parameters to accept a function that throws?
The problem is that Java has checked exceptions but Kotlin does not. The requestFunc parameter type () -> List<Widget> will be mapped to the functional interface Function0<List<Widget>> but the operator invoke doesn't throw a checked exception in Kotlin code.
So you can't call the getStaticWidgets() in lambda expression since it throws a IOException which is a checked exception in Java.
Since you control both the Kotlin and Java code, the simplest solution is to change the parameter type () -> List<Widget> to Callable<List<Widget>>, for example:
// change the parameter type to `Callable` ---v
fun convertExceptionToEmpty(requestFunc: Callable<List<Widget>>): Stream<Widget> {
try {
// v--- get the `List<Widget>` from `Callable`
return requestFunc.call().stream()
} catch (th: Throwable) {
return Stream.empty()
}
}
Then you can use Method Reference Expression in Java8 as further, for example:
Stream<Widget> widgets = convertExceptionToEmpty(this::getStaticWidgets);
//OR if `getStaticWidgets` is static `T` is the class belong to
// v
Stream<Widget> widgets = convertExceptionToEmpty(T::getStaticWidgets);
I'm afraid there's nothing you can do but catch that exception :
Stream<Integer> widgets = convertExceptionToEmpty(() -> {
try {
return getStaticWidgets();
} catch (IOException e) {
e.printStackTrace();
}
return null;
});
I am trying to load methods Customer.cypher and Customer.cypherCBC method from my class Configuration. Customer class is rendering from different environments so few environmets are having cypherCBC() and cypher() method and few are having only cypher() method.
Now i want to check if cypherCBC if not there in Customer class then load cypher() method. My function is so far;
try {
Class<?> customerClass = Class.forName("com.myapp.impl.service.Customer");
Object obj = customerClass.newInstance();
//here getting "NoSuchMethodException" exception
Method methodCBC = customerClass.getDeclaredMethod("cypherCBC", String.class); //line - 7
if(methodCBC.getName().equals("cypherCBC")){
methodCBC.invoke(obj, new String(dbshPass));
System.out.println("CYPHER_CBC: "
+ methodCBC.invoke(obj, new String(dbshPass)));
}else{
Method method = customerClass.getDeclaredMethod("cypher", String.class);
method.invoke(obj, new String(dbshPass));
System.out.println("CYPHER: " + method.invoke(obj, new String(dbshPass)));
}
}catch (Exception e){
e.printStackTrace();
}
Getting an error at line 7.
NoSuchMethodException:
com.myapp.impl.service.Customer.cypherCBC(java.lang.String)
that means for particular environment class Customer doesn't having cypherCBC() method, but ideally it should come in else part and execute cypher() method.
Class<?> client = null;
Object obj = null;
try{
client = Class.forName("com.myapp.impl.service.Client");
obj = client.newInstance();
}catch (InstantiationException ex) {
System.err.println("Not able to create Instance of Class");
} catch (IllegalAccessException ex) {
System.err.println("Not able to access Class");
} catch (ClassNotFoundException ex) {
System.err.println("Not able to find Class");
}
try {
Method methodCBC = client.getDeclaredMethod("cypherCBC", String.class);
System.out.println("CYPHER_CBC: " + methodCBC.invoke(obj, new String(dbshPass)));
}catch (NoSuchMethodException ex) {
System.err.println("Not able to find Method on class");
ex.printStackTrace();
} catch (Exception e){
e.printStackTrace();
}
That is exactly what is to be expected: getDeclaredMethod() throws that exception when no method exists that meets your specification. And you are wondering that it throws an exception if the required method is missing? Hint: better read the javadoc next time. Don't assume that something does something, but verify your assumptions!
Besides: read your code again. What is it doing? You are asking "give me the method named 'foo'". And then, your next step is to ask that method "is your name 'foo'". So even without reading javadoc, it should become clear that your logic is flawed.
As solution, you can implement a non-throwing lookup yourself, like
private Method lookupCypher(Class<?> client, String methodName) {
for (Method declaredMethod : client.getDeclardMethods()) {
if (declaredMethod.getName().equals(methodName)) {
Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
if (parameterTypes.length == 1 && parameterTypes[0].equals(String.class)) {
// so declaredMethod has the given name, and takes one string as argument!
return declaredMethod;
}
}
// our search didn't reveal any matching method!
return null;
}
Using that helper method, you can rewrite your code to:
Method toInvoke = lookupCypher(client, "cypherCBC");
if (toInvoke == null) {
toInvoke = lookupCypher(client, "cypher");
}
toInvoke(obj, new String ...
Or, with the idea from hunter in mind; a much more "OO like" version:
interface CustomerCypherWrapper {
void cypher(String phrase);
}
class NewCustomerWrapper() implements CustomerCypherWrapper {
#Override
void cypher(String phrase) {
new Customer.cypherCBC(phrase);
}
}
class oldCustomerWrapper() implements CustomerCypherWrapper {
#Override
void cypher(String phrase) {
new Customer.cypher(phrase);
}
}
And your client code boils down to:
CustomerCypherWrapper wrapper =
(lookupCypher(..., "cypherCBC") == null)
? new NewCustomerWrapper()
: new OldCustomerWrapper();
wrapper.cypher();
[ I hope you notice that my version A) is easier to read and B) doesn't contain any duplicated code any more. ]
And yes, an alternative implementation of the lookup method could just go like
private Method lookupCyper(Client<?>, String methodName) {
try {
return client.getDeclaredMethod(methodName, String.class);
} catch ....
and return null;
}
... return your public cypherCBC method
But that is an "uncommon practice" in Java. In Java, we ask for permission; instead of forgiveness. Unlike other languages
if you compile the application with a Customer class which has both method,you can use reflection once to check whether the cypherCBC method available or not at runtime, then you can keep that status, you can call the method without using reflection
if(newVersion)
{
customer.cypherCBC(arg);
}
else
{
customer.cypher(arg);
}
But to write a better application,you should use two version baselines.
even though this is a small code fragment you should setup a another module to hide this Customer class and its interactions,that module should have two versions. but your main module has only single version.Now when you you deliver the application , product should be packaged with right version baseline based on compatibility for the target environment.
Although reflection works (as explained in the other answers). if you have control over the Customer class, you can try a non-reflection approach.
interface CBCCypherable {
public String cypherCBC(String pass);
}
You can now have two versions of Customer class, one that implements CBCCypherable and one that doesn't. And when you call it, it looks like this:
Customer c = new Customer();
if (c instanceof CBCCypherable) {
((CBCCypherable)c).cypherCBC(pass);
} else {
c.cypher(pass);
}
What you get with this solution is much simpler code, and as a bonus the compiler will check that you use the correct method name and parameter types. Unlike with reflection, where that's all your job, and you have to run the code to find out if something's wrong.
P.s.: I don't know if this is just sample code or you are really encrypting/hashing passwords here, but it's generally considered a bad idea to roll your own security code.
How can I iterate over the attributes of an object, with the attribute names provided in a list/array - NOT all attributes, like using reflection & getDeclaredFields().
public class MyClass
{
public type1 att1;
public type2 att2;
public type3 att3;
public MyClass(
att1="helo";
att2="bye";
att3="morning";
);
...
public void function()
{
String myStrings[];
myStrings = new String[] { "att2", "att3" };
MyClass myobject = new MyClass();
for(var in myStrings)
{
System.out.println(var);
System.out.println(myobject.var);
System.out.println();
}
}
}
Your question is somewhat ambiguous about using reflection. If you are OK with reflection, but want specific fields only without iterating over getDeclaredFields(), then the following code should work for you:
for (String var : myStrings) {
Field field = MyClass.class.getDeclaredField(var);
field.setAccessible(true);
System.out.println(var);
System.out.println(field.get(myObject));
System.out.println();
}
Note that this code works for private fields, too. Also, keep in mind that you'll have to handle exception associated with the reflection calls.
UPDATE: Exceptions thrown in this code.
MyClass.class.getDeclaredField(var) declares a checked NoSuchFieldException. You must handle it because obviously there is no mechanism to make sure that the fields in myString match an actual implementation of MyClass.
field.get(myObject) throws a checked IllegalAccessException if the field is inaccessible. Which it should not be because of field.setAccessible(true), but you still have to catch or re-throw the exception.
There are also unchecked exceptions you may want to handle. See the javadoc for details
java.lang.Class.getDeclaredField(String)
java.lang.reflect.AccessibleObject.setAccessible(boolean) inherited by java.lang.reflect.Field
java.lang.reflect.Field.get(Object)
You probably want to use some technology that builds on top of JavaBeans / BeanInfo. Apache Commons / BeanUtils is a good starting point here.
Please refer to this previous answer of mine for more info:
https://stackoverflow.com/a/5856982/342852
But if you just want to use fields, not bean properties, here's a Java 8 method to do so:
public static Map<String, Object> getFieldProperties(Object o, Collection<String> fields) {
Class<?> type = o.getClass();
return fields.stream().map(n -> {
try {
return type.getDeclaredField(n);
} catch (NoSuchFieldException e) {
throw new IllegalStateException(e);
}
}).collect(Collectors
.toMap(
(Function<Field, String>) Field::getName,
(Function<Field, Object>) field -> {
try {
field.setAccessible(true);
return field.get(o);
} catch (IllegalAccessException e) {
throw new IllegalStateException(e);
}
}));
}
Unfortunately the checked exceptions make this more verbose than it would need to be.
Let's say I'd like to perform the following command:
house.getFloor(0).getWall(WEST).getDoor().getDoorknob();
To avoid a NullPointerException, I'd have to do the following if:
if (house != null && house.getFloor(0) && house.getFloor(0).getWall(WEST) != null
&& house.getFloor(0).getWall(WEST).getDoor() != null) ...
Is there a way or an already existing Utils class that does this more elegantly, let's say something like the following?
checkForNull(house.getFloor(0).getWall(WEST).getDoor().getDoorknob());
In case you can't avoid breaking Law of Demeter (LoD) as stated in the chosen answer, and with Java 8 introducing Optional, it would be probably the best practice to handle nulls in chains of gets such as yours.
The Optional type will enable you to pipe multiple map operations (which contain get calls) in a row. Null checks are automatically handled under the hood.
For example, when the objects aren't initialized, no print() will be made and no Exceptions will be thrown. It all we be handled gently under the hood. When objects are initialized, a print will be made.
System.out.println("----- Not Initialized! -----");
Optional.ofNullable(new Outer())
.map(out -> out.getNested())
.map(nest -> nest.getInner())
.map(in -> in.getFoo())
.ifPresent(foo -> System.out.println("foo: " + foo)); //no print
System.out.println("----- Let's Initialize! -----");
Optional.ofNullable(new OuterInit())
.map(out -> out.getNestedInit())
.map(nest -> nest.getInnerInit())
.map(in -> in.getFoo())
.ifPresent(foo -> System.out.println("foo: " + foo)); //will print!
class Outer {
Nested nested;
Nested getNested() {
return nested;
}
}
class Nested {
Inner inner;
Inner getInner() {
return inner;
}
}
class Inner {
String foo = "yeah!";
String getFoo() {
return foo;
}
}
class OuterInit {
NestedInit nested = new NestedInit();
NestedInit getNestedInit() {
return nested;
}
}
class NestedInit {
InnerInit inner = new InnerInit();
InnerInit getInnerInit() {
return inner;
}
}
class InnerInit {
String foo = "yeah!";
String getFoo() {
return foo;
}
}
So, with your getters chain it will look like this:
Optional.ofNullable(house)
.map(house -> house.getFloor(0))
.map(floorZero -> floorZero.getWall(WEST))
.map(wallWest -> wallWest.getDoor())
.map(door -> wallWest.getDoor())
The return of it will be something like Optional<Door> which will allow you much safer work without worrying of null exceptions.
In order to check a chain of gets for null you may need to call your code from a closure. The closure call code will look like this:
public static <T> T opt(Supplier<T> statement) {
try {
return statement.get();
} catch (NullPointerException exc) {
return null;
}
}
And you call it using the following syntax:
Doorknob knob = opt(() -> house.getFloor(0).getWall(WEST).getDoor().getDoorknob());
This code is also type safe and in general works as intended:
Returns an actual value of the specified type if all the objects in the chain are not null.
Returns null if any of the objects in the chain are null.
You may place opt method into shared util class and use it everywhere in your application.
The best way would be to avoid the chain. If you aren't familiar with the Law of Demeter (LoD), in my opinion you should. You've given a perfect example of a message chain that is overly intimate with classes that it has no business knowing anything about.
Law of Demeter: http://en.wikipedia.org/wiki/Law_of_Demeter
You could of course simply wrap the whole expression up in a try-catch block, but that's a bad idea. Something cleaner is the Null object pattern. With that, if your house doesn't have floor 0, it just returns a Floor that acts like a regular Floor, but has no real content; Floors, when asked for Walls they don't have, return similar "Null" Walls, etc, down the line.
Make sure things that can't logically be null are not. For example - a house always has a West wall. In order to avoid such exceptions in state, you can have methods to check whether the state you expect is present:
if (wall.hasDoor()) {
wall.getDoor().etc();
}
This is essentially a null-check, but might not always be.
The point is that you should do something in case you have a null. For example - return or throw an IllegalStateException
And what you shouldn't do - don't catch NullPointerException. Runtime exceptions are not for catching - it is not expected that you can recover from them, nor it is a good practice to rely on exceptions for the logic flow. Imagine that you actually don't expect something to be null, and you catch (and log) a NullPointerException. This will not be very useful information, since many things can be null at that point.
Better solution for me is to use java.util.Optional.map(..) to chain these checks : https://stackoverflow.com/a/67216752/1796826
There is no checkForNull method that you can write that will facilitate this (that's simply not how method invokation and argument evaluation works in Java).
You can break down the chained statements into multiple statements, checking at every step. However, perhaps a better solution is to not have these methods return null in the first place. There is something called the Null Object Pattern that you may want to use instead.
Related questions
How to avoid != null statements in Java?
You could potentially have a generic method like below:
public static <T> void ifPresentThen(final Supplier<T> supplier, final Consumer<T> consumer) {
T value;
try {
value = supplier.get();
} catch (NullPointerException e) {
// Don't consume "then"
return;
}
consumer.accept(value);
}
So now you would be able to do
ifPresentThen(
() -> house.getFloor(0).getWall(WEST).getDoor().getDoorknob(),
doorKnob -> doSomething());
implementing nullPointer try/catch with a Supplier you can send it all chain of get
public static <T> T getValue(Supplier<T> getFunction, T defaultValue) {
try {
return getFunction.get();
} catch (NullPointerException ex) {
return defaultValue;
}
}
and then call it in this way.
ObjectHelper.getValue(() -> object1.getObject2().getObject3().getObject4()));
Very old question, but still adding my suggestion:
I would suggest instead of getting the DoorKnob from deep within the House in one method call chain, you should try to let the DoorKnob be provided to this class from the calling code, or by creating a central lookup facility specifically for this purpose (e.g. a DoorKnob service)
Simplified example of design with loose coupling:
class Architect {
FloorContractor floorContractor;
void build(House house) {
for(Floor floor: house.getFloors()) {
floorContractor.build(floor);
}
}
}
class FloorContractor {
DoorMaker doorMaker;
void build(Floor floor) {
for(Wall wall: floor.getWalls()) {
if (wall.hasDoor()) {
doorMaker.build(wall.getDoor());
}
}
}
}
class DoorMaker {
Tool tool;
void build(Door door) {
tool.build(door.getFrame());
tool.build(door.getHinges());
tool.build(door.getDoorKnob());
}
}
// Example
LazyObject.from(curr).apply(A.class, A::getB).apply(B.class, B::getC).apply(C.class, C::getD).to(String.class);
// LazyObject.java
public class LazyObject {
private Object value;
private LazyObject(Object object) {
this.value = object;
}
public <F, T> LazyObject apply(Class<F> type, Function<F, T> func) {
Object v = value;
if (type.isInstance(v)) {
value = func.apply(type.cast(v));
} else {
value = null; // dead here
}
return this;
}
public <T> void accept(Class<T> type, Consumer<T> consumer) {
Object v = value;
if (type.isInstance(v)) {
consumer.accept(type.cast(v));
}
}
public <T> T to(Class<T> type) {
Object v = value;
if (type.isInstance(v)) {
return type.cast(v);
}
return null;
}
public static LazyObject from(Object object) {
return new LazyObject(object);
}
}