Created
October 14, 2022 08:51
-
-
Save hugithordarson/21e18e9746948da00034d03d71620bf9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package x; | |
import java.lang.reflect.Method; | |
import java.util.Collections; | |
import java.util.List; | |
public class KVCBastardization { | |
public enum Color { | |
Red { | |
@Override | |
public String someInstanceMethod() { | |
return "I am red"; | |
} | |
}; | |
public abstract String someInstanceMethod(); | |
} | |
public static void main( String[] args ) throws Exception { | |
System.out.println( Color.class ); | |
System.out.println( Color.Red.getClass() ); | |
System.out.println( valueForKey( Color.Red, "someInstanceMethod" ) ); | |
} | |
public static void mains( String[] args ) throws Exception { | |
System.out.println( valueForKey( Collections.emptyList(), "size" ) ); | |
System.out.println( valueForKey( List.of( "Item" ), "size" ) ); | |
} | |
public static Object valueForKey( Object object, String key ) throws Exception { | |
return accessibleMethodForKey( object, key ).invoke( object ); | |
} | |
private static Method accessibleMethodForKey( Object object, String key ) throws NoSuchMethodException, SecurityException { | |
Class<?> classToUseForLocatingMethod = object.getClass(); | |
try { | |
while( classToUseForLocatingMethod != null ) { | |
Method classMethod = classToUseForLocatingMethod.getMethod( key ); | |
if( classMethod.canAccess( object ) ) { | |
// This is the happy path, where we'll immediately end up in 99% of cases | |
return classMethod; | |
} | |
// Here come the dragons... | |
// The class doesn't have an accessible method definition. What about the interfaces? | |
for( Class<?> interfaceClass : classToUseForLocatingMethod.getInterfaces() ) { | |
try { | |
final Method interfaceMethod = interfaceClass.getMethod( key ); | |
if( interfaceMethod.canAccess( object ) ) { | |
return interfaceMethod; | |
} | |
} | |
catch( Exception interfaceException ) { | |
// Failure to locate methods in interfaces are to be expected. If no interfaces contain the method, we've already failed anyway. | |
} | |
} | |
// Now let's try the whole thing again for the superclass | |
classToUseForLocatingMethod = classToUseForLocatingMethod.getSuperclass(); | |
} | |
} | |
catch( NoSuchMethodException | SecurityException methodException ) { | |
// If the method doesn't exist on the original class we're dead whatever we do regardless of accessibility, so just throw immediately | |
throw methodException; | |
} | |
// FIXME: Don't throw | |
return null; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment