I have a little problem with default methods in Interface and BeanInfo Introspector.
In this example, there is interface: Interface
public static interface Interface {
default public String getLetter() {
return "A";
}
}
and two classes ClassA and ClassB:
public static class ClassA implements Interface {
}
public static class ClassB implements Interface {
public String getLetter() {
return "B";
}
}
In main method app prints PropertyDescriptors from BeanInfo:
public static String formatData(PropertyDescriptor[] pds) {
return Arrays.asList(pds).stream()
.map((pd) -> pd.getName()).collect(Collectors.joining(", "));
}
public static void main(String[] args) {
try {
System.out.println(
formatData(Introspector.getBeanInfo(ClassA.class)
.getPropertyDescriptors()));
System.out.println(
formatData(Introspector.getBeanInfo(ClassB.class)
.getPropertyDescriptors()));
} catch (IntrospectionException e) {
e.printStackTrace();
}
}
And the result is:
class
class, letter
Why default method "letter" is not visible as property in ClassA? Is it bug or feature?
I guess, Introspector does not process interface hierarchy chains, even though with Java 8 virtual extention methods (aka defenders, default methods) interfaces can have something that kinda sorta looks like property methods. Here's a rather simplistic introspector that claims it does: BeanIntrospector
Whether this can be considered a bug is somewhat of a gray area, here's why I think so.
Obviously, now a class can "inherit" from an interface a method that has all the qualities of what's oficially considered a getter/setter/mutator. But at the same time, this whole thing is against interface's purpose -- an interface can not possibly provide anything that can be considered a property, since it's stateless and behaviorless, it's only meant to describe behavior. Even defender methods are basically static unless they access real properties of a concrete implementation.
On the other hand, if we assume defenders are officially inherited (as opposed to providing default implementation which is a rather ambiguous definition), they should result in synthetic methods being created in the implementing class, and those belong to the class and are traversed as part of PropertyDescriptor lookup. Obviously this is not the way it is though, otherwise the whole thing would be working. :) It seems that defender methods are getting some kind of special treatment here.
Debugging reveals that this method is filtered out at Introspector#getPublicDeclaredMethods():
if (!method.getDeclaringClass().equals(clz)) {
result[i] = null; // ignore methods declared elsewhere
}
where clz is a fully-qualified name of the class in question.
Since ClassB has custom implementation of this method, it passes the check successfully while ClassA doesn't.
I think also that it is a bug.
You can solve this using a dedicated BeanInfo for your class, and by providing somthing like that :
/* (non-Javadoc)
* #see java.beans.SimpleBeanInfo#getAdditionalBeanInfo()
*/
#Override
public BeanInfo[] getAdditionalBeanInfo()
{
Class<?> superclass = Interface.class;
BeanInfo info = null;
try
{
info = Introspector.getBeanInfo(superclass);
}
catch (IntrospectionException e)
{
//nothing to do
}
if (info != null)
return new BeanInfo[] { info };
return null;
}
This is because you only have your method on Interface and ClassB, not on ClassA directly. However it sounds to me like a bug since I'd expect that property to showup on the list. I suspect Inrospector did not catch up with Java 8 features yet.
Related
I define an interface follow
interface SdkInterface {
void onPause();
void onResume();
void onStop();
}
then I define a abstract class implement the interface
abstract class BaseCore implements SdkInterface {
public static final byte[] lock = new byte[0];
private static final String TAG = "BaseCore";
public static Core instance;
#Override
public void onPause() {
Log.e(TAG, "onPause: ");
}
#Override
public void onResume() {
Log.e(TAG, "onResume: ");
}
#Override
public void onStop() {
Log.e(TAG, "onStop: ");
}
}
then I has a class extends the abstract class
class Core extends BaseCore {
private Core() {
}
public static Core getInstance() {
if (instance == null) {
synchronized (lock) {
if (instance == null) {
instance = new Core();
}
}
}
return instance;
}
}
now I want to generate a proxy for the instance field of the BaseCore class,I do this
public static void register() {
try {
Class<?> core = Class.forName("com.secoo.coobox.Core");
Field instance = core.getSuperclass().getDeclaredField("instance");
Method getInstance = core.getDeclaredMethod("getInstance");
Object invoke = getInstance.invoke(null);
Object o = Proxy.newProxyInstance(core.getClassLoader(), core.getInterfaces(), new InvocationHandler() {
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Log.e("BaseCore", "invoke: before " + method.getName());
Object invoke1 = method.invoke(invoke, args);
Log.e("BaseCore", "invoke: after " + method.getName());
return invoke1;
}
});
instance.set(invoke, o);
} catch (ClassNotFoundException | NoSuchFieldException | NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
but I receive the exception
Caused by: java.lang.IllegalArgumentException: field com.secoo.coobox.BaseCore.instance has type com.secoo.coobox.Core, got $Proxy2
at java.lang.reflect.Field.set(Native Method)
at com.secoo.coobox.TestProxy.register(TestProxy.java:31)
at com.secoo.coobox.MainActivity.onCreate(MainActivity.kt:24)
at android.app.Activity.performCreate(Activity.java:8006)
at android.app.Activity.performCreate(Activity.java:7990)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1329)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3584)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3775)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2246)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:233)
at android.app.ActivityThread.main(ActivityThread.java:8010)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:631)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:978)
who can help me explain the excetion and how I can solve the problem? thanks
Your code has serious style issues, and it is broken. And we haven't even gotten to the error you're asking about yet. I suggest you skip the actual answer and instead read why you're barking up the wrong tree and need to rethink this code, making the actual answer irrelevant for you.
The actual answer
Proxy will make a new instance of a proxy class (that's where that $Proxy2 thing is coming from). Proxy cannot make an object that is an instance of that actual class: That's just not how java works. Thus, you have an instance of an unknown, effectively irrelevant class. However, that $Proxy2 class does implement whatever interfaces you want it to. It can't extend anything (other than, obviously, java.lang.Object). No final classes, no normal classes, not even abstract classes. That's just how it works: If you want a proxy that extends something specific, you're out of luck.
Thus: You can only proxy interfaces.
Had the field been:
public static SdkInterface instance;
instead, it would have worked fine; That $Proxy2 class is a class made on the fly by the Proxy.newProxyInstance call, and this class implements all the interface you passed in.
But, as I said, do not just start changing things, you need to rethink this code more fundamentally.
The more significant issues with your code
Your BaseCore class has a field of type Core, eliminating any point or purpose in the class hierarchy of it. Its type should possible be BaseCore, or the 'singleton holder' field should be in Core. Generally fields should have the least specific type that you want to use, e.g. we write List x = new ArrayList - because List is less specific. You've gone the other way, and made the field the most specific type you could find (Core, which is more specific than BaseCore, which is more specific than SdkInterface). If that static field's type is SdkInterface, you can assign a proxy object to it. But if the type of that field is a class (other than java.lang.Object), then that is impossible - as proxies implement whatever interfaces you want, but extend j.l.Object and can't be made to extend anything else.
Double checked locking does not work, so don't do it. Your getInstance() method is broken in a really nasty way: It is broken, but, most tests do not catch it. It requires a specific combination of hardware, android version, and phase of the moon for it to fail. There are only 2 sane ways to 'load' singletons: Generally, just initialize the field (and make it final), because java lazy loads; the only benefit to having an actual method that loads it only when you invoke .getInstance() or whatnot, is when it is plausible you will 'touch' the class (load a class that has a field of type Core, for example), but never actually need the instance. This happens, but it is rare. If it doesn't apply to you, there is no point to any of this, and you can just write public static final Core INSTANCE = new Core(); and be done with it all. If you really do need the getSingleton method, use the java classloader which is extremely good at efficient locking - at least as good as anything you can write in java and possibly better:
public static Core get() {
return CoreSingletonHolder.INSTANCE;
}
private static class CoreSingletonHolder {
static final Core INSTANCE = new Core();
}
This works because java doesn't load classes until it is needed, and nothing 'touches' CoreSingletonHolder (causing it to be loaded), except invoking the get() method. Hence, new Core() is executed exactly once, and only once, as per JVM guarantees, using ClassLoader's own locking mechanism, which is very efficient. It's efficient because java has to do this with every single last class your app ever loads. If it wasn't efficient, java/android would be dog slow, and we know it isn't, QED.
Your intended singleton instance is public and non-final; anything can overwrite it. The above strategies fix these issues; given that all access needs to go through get() in order to ensure its initialized, why make it public?
I have an object model made up of interfaces with getter/setter methods. Implementations of these objects are created using dynamic proxies where values for the fields implied (using JavaBean naming conventions) are stored in a Map.
I'd like to add methods to these interfaces to provide business logic (you know, like a real object model and not just a collection of POJOs).
My first thought was to create abstract classes that implement each interface but only provide implementations of the business methods. Then I would use these implementations in concert with the Map in the InvocationHandler to provide a full implementation of the interface.
Something like:
interface ModelObject extends BaseModel {
void setFoo(String foo);
String getFoo();
void doSomething();
}
public abstract class ModelObjectImpl implements ModelObject {
#Override
public void doSomething()
{
// Do something
}
}
public class ModelObjectInvocationHander implements InvocationHandler {
Map<String, Object> fieldValues; // holds values for implied fields for getter setter
ModelObject modelObject; // holds reference to object implementing business methods
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// Get implied field name for method name by removing "get"/"set" and lower casing next letter
String fieldName = getBeanNameForMethod(method.getName());
if (fieldValues.containsKey(fieldName)) {
return fieldValues.get(fieldName);
}
// Not a getter/setter so must be a business method. Delegate to implementation class
return method.invoke(modelObject, args);
}
}
Something like this (but obviously more complicated) would work except that I cannot create an instance of the abstract class. I could make BusinessObjectImpl non-abstract and add do-nothing implementations of the getter/setter methods that would never be called, but that just uglies up the code and causes maintenance issues. I could also have BusinessObjectImpl not actually implement the BusinessObject interface but that breaks the nice binding between implementation and interface leading to errors when the interface and "implementation" get out of sync.
Are there any sneaky Java Reflection tricks I can use to invoke these business methods?
UPDATE:
Went with a combination of the Java dynamic proxy framework that's already in place and Javassist to create proxies for the abstract implementation classes. This allows there to be no changes at all to the existing model interfaces until business methods are added on an as-needed basis. The capability is now in place to add behavior to the objects. It's up the developers to start writing true object oriented code now.
public class ModelObjectInvocationHandler implements InvocationHandler
{
public ModelObjectInvocationHandler(Class<ModelImplementation<? extends BaseModel>> implementationClass)
{
if (implementationClass != null)
{
ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(implementationClass);
try
{
modelObject = (ModelObject) factory.create(new Class<?>[0], new Object[0]);
}
catch (Exception e)
{
// Exception handling
}
}
}
Map<String, Object> fieldValues; // holds values for implied fields for getter setter
ModelObject modelObject; // holds reference to object implementing business methods
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
// Get implied field name for method name by removing "get"/"set" and lower casing next letter
String fieldName = getBeanNameForMethod(method.getName());
if (fieldValues.containsKey(fieldName))
{
return fieldValues.get(fieldName);
}
// Not a getter/setter so must be a business method. Delegate to implementation class
if (modelObject != null)
{
return method.invoke(modelObject, args);
}
return null;
}
}
At runtime, I scan for implementation classes and create a Map<Class<? extends BaseModel>, Class<ModelImplementation>>. When creating the dynamic proxy for the interface, I find its implementation class in the map and pass it to the InvocationHandler. Any method that is not matched as a bean name is delegated to the proxy for the implementation class. Of course, it's a little more complicated than that since I have to account for class hierarchies and multiple inheritance within the model interfaces, but the theory is sound.
I'm not aware of any standard Java reflection tricks that would do that. You could dynamically extend the abstract classes using cglib or javaassist at class load-time. This would improve performance a little bit, because no Proxy object is necessary anymore. Instead you can implement the getter/setter methods directly when creating the new class.
A third way, without those tricks, would be with the delegation pattern:
public class ModelObjectImpl implements ModelObject {
private final ModelObject delegate;
public ModelObjectImpl(ModelObject delegate) {
this.delegate = delegate;
}
#Override
public void doSomething() { /* Do something */ }
#Override
public String getFoo() { return delegate.getFoo(); }
#Override
public void setFoo(String foo) { delegate.setFoo(foo); }
}
Feed your proxy, implementing the getter/setter methods of the interface, to the constructor delegate argument. However, while this looks better than stub methods (at least for me) it's still duplicate code. So if you really want to have such dynamic classes, go with dynamic bytecode generation.
References:
Delegation pattern
CGLib
Javaassist
One way to do that is to define all your "additional" or "business" method's contract in a new interface, like:
interface ModelObjectExtension {
void doSomething();
}
interface ModelObject extends ModelObjectExtension {
void setFoo(String foo);
String getFoo();
}
public abstract class ModelObjectExtensionImpl implements ModelObjectExtension {
#Override
public void doSomething()
{
// Do something
}
}
public class ModelObjectImpl extends ModelObjectExtension {
// whatever your current implementation is...
}
and finally you can use following in your handler to call extension methods:
((ModelObjectExtension) modelObject).doSomething();
This might seem like an odd thing to want, but is there a way in Java to stop subclasses from adding new methods (including constructors) whilst still allowing subclasses to override methods?
The actual situation is where we have an abstract class with some abstract methods and a constructor
abstract class A {
abstract A doX();
abstract boolean isY();
public A(String s){ ... };
}
and we want all concrete subclasses of this class to only override these methods and constructor.
This is about enforcing a certain style in our code i.e. stopping other people working on the code from adding things. We could just tell them not to, but that rarely works, so we wondered if there was a programmatic way of achieving this.
Obviously the class cannot be final. Efficiency isn't paramount - cleaner code is more important.
Update - dynamic approach
As has been pointed out in the answers, there is no way to do this statically as the only way to prevent subclasses being created is using final, which won't work. But I could use a dynamic approach so my current solution is to add this aspect to the project (which already uses AspectJ).
public aspect WatchA{
before() : execute(* A.*()) || execute(* A.*(..)) {
String methodCalled = joinPoint.getSignature().getName();
Class<?> c = Class.forName(args[0])
Method[] allMethods = c.getDeclaredMethods();
boolean found = false;
for(Method m : allMethods)
found |= m.getName().equals(methodCalled);
if(!found)
throw new RuntimeException("Do not add method "+methodCalled+" to A");
}
}
Which will cause their tests to fail if they use any of these new methods.
You cannot do that. Only if classes are final can you ensure that no subclass can be created.
You can also make methods final (even in abstract classes) so that overriding them is forbidden.
Your best bet is to create an interface, with all methods you want visible, and force all users of your API to access the objects via this interface. This way, even if implementations add their own stuff, said stuff won't be visible.
One solution for this is to implement a factory to return the concrete classes; for "added security", you could put all implementations in the same package as this factory and make constructors package local (but this is often not practical):
public final class MyFactory
{
// ....
public MyInterface getConcrete()
{
return new MyInterfaceImpl();
}
// etc etc -- getStones(), getTar(), getFeathers() and so on
}
Note that builders can also be used for that.
If you really wan't to do this.. one way would be to programatically check in the abstract class constructor that the methods defined in the class are those that are allowed.
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public abstract class Base {
private static final Set<String> allowedMethodNames = new HashSet<>(Arrays.asList("doThis", "wait", "wait", "wait", "equals", "toString", "hashCode", "getClass", "notify", "notifyAll"));
public Base() {
Set<String> allMethods = new HashSet<>();
for (Method aMethod : getClass().getMethods()) {
allMethods.add(aMethod.getName());
}
if (!allowedMethodNames.equals(allMethods)) {
allMethods.removeAll(allowedMethodNames);
throw new IllegalStateException("Following methods not allowed <" + allMethods + ">");
}
}
public abstract void doThis();
}
public class Disallowed extends Base {
#Override
public void doThis() {
System.out.println("dooooooo");
}
public void doSomethingElse() {
System.out.println("not allowed");
}
public static void main(String[] args) {
new Allowed().doThis();
new Disallowed();
}
}
public class Allowed extends Base {
#Override
public void doThis() {
System.out.println("doing this");
}
}
When someone is trying create an instance of 'Disallowed' it would fail. However 'new Allowed().doThis()' will work fine.
A more graceful way to do this would be to introduce a custom annotation + annotation processor and do the same check during the compilation time.
There is no such way.
Why would you want to enforce such a coding style?
If you really must enforce such a style you could create a "rule enforcer" which checks your classpath and compares the methods of your abstract parent classes with their sub classes.
It is Java which means flexibility. So java gives you more convinient in using the abstract methods and overriding them from your subclasses. Also one should have an idea of adding new methods to these subclasses. Even java can't change this. If it does then the whole Java community crash. It is impossible that you can prevent from adding methods to their subclasses. Only you can stop them extending your classes and overridding your methods.
I have a class that implements an interface. There's another class that implements this interface, too, and an instance of this second class backs my class's implementation.
For many of the methods specified by the interface, my class simply forwards them straight to the second class.
public class MyClass implements MyInterface
{
private OtherClass otherClassInstance; // Also implements MyInterface.
// ...
void foo() { otherClassInstance.foo(); }
void bar() { otherClassInstance.bar(); }
void baz() { otherClassInstance.baz(); }
// ...
}
Simply deriving my class from the second class would eliminate all of this, but it doesn't make sense because the two classes are unrelated to each other (besides implementing a common interface). They represent different things - it just so happens that a lot of my class's implementation copies that of the other class. In other words, my class is implemented atop the second class, but it is not itself a subset of the second class. As we know, inheritance is meant to express an "is-a" relationship, not to share implementation, so it's inappropriate in this case.
This portion of a talk by Joshua Bloch illustrates the situation well.
I know that Java doesn't have any language support for delegation. However, is there at least some way to clean up my class's implementation so it isn't so redundant?
An answer which is not really an answer to your actual question:
I'd say, live with the boilerplate. Let IDE generate it for you. Example: in Netbeans, add the private ArrayList field, set cursor to where you'd want the methods to appear, hit alt-insert, select "Generate Delegate Method...", click the methods you want to create a delegate for in the dialog opens, submit, go through the generated methods and make them do the right thing, you're done.
It is a bit ugly, but it is still preferable to starting to mess with reflection, when you are dealing with just one class, like it sounds. Your class is probably the kind of class, which you will complete and fully test, and then hopefully never touch again. Reflection creates runtime cost which does not go away. Suffering the auto-generated boilerplate in the source file is probably preferable in this case.
First way to use http://java.sun.com/javase/6/docs/api/java/lang/reflect/Proxy.html see tutorial http://docs.oracle.com/javase/1.4.2/docs/guide/reflection/proxy.html
Second way using AOP you can create dispatcher that intercept all invocation of specific class
For both ways you need to manage methods processing using reflection API
EDITED TO SHOW IDEA
Following code taken from tutorial above just modified a little (see youListImpl.getRealArrayList() in invoke method)
public class DebugProxy implements java.lang.reflect.InvocationHandler {
private YouListImpl youListImpl;
public static Object newInstance(Object obj) {
return java.lang.reflect.Proxy.newProxyInstance(
obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),
new DebugProxy(obj));
}
private DebugProxy(Object obj) {
this.obj = obj;
}
public Object invoke(Object proxy, Method m, Object[] args)
throws Throwable
{
Object result;
try {
System.out.println("before method " + m.getName());
result = m.invoke(youListImpl.getRealArrayList(), args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
} catch (Exception e) {
throw new RuntimeException("unexpected invocation exception: " +
e.getMessage());
} finally {
System.out.println("after method " + m.getName());
}
return result;
}
}
I have a factory method that creates objects to be used in unit tests. These objects all derive from the same base class:
public static <T extends BaseEntity> T modMake(Class<T> clazz)
{
try {
return clazz.newInstance();
} catch (InstantiationException e) {
// Should never happen
throw new AssertionError(e);
} catch (IllegalAccessException e) {
// Should never happen
throw new AssertionError(e);
}
}
Now I want to override a getter method from that base class, but just for the tests. I would usually do that with an anonymous class, for example (Node being one of the subtaypes of BaseEntity):
public static Node nodMake()
{
return new Node() {
#Override
public long ixGet() { return 1; }
};
}
Can I do that in the function using the Class argument, too?
Lose your factory method and use a mocking API like EasyMock to achieve the behavior you describe.
Your code will then end up something like this:
long returnValue = 12;
Node nodeMock = createMock(Node.class);
expect(nodeMock.ixGet()).andReturn(returnValue);
replay(nodeMock);
//add test code here
verify(nodeMock);
To answer Hanno's question on how this works:
It depends on whether your mocking an interface or a class.
The case of the interface is simple (code-wise), it uses what's called a dynamic proxy, which is part of core Java.
In the case of the class it's doing the bytecode manipulation that #Jonathan mentions in his answer, just behind a nice API.
Both the above mechanisms allow the method calls to be intercepted and EasyMock simply responds based on the expectations you've setup.
I don't think there is any way to do that. You probably need to look into bytecode manipulators if you really need to go that route. Javassist and BCEL are a couple of choices.