6
I’ve had a lot of fun creating interface proxies in Java. For example, the following proxy was required on Sqldroid to run version 5.2.4 of Flyway (and also to catch the path of the file created by the driver):
// interface para pegar o path do arquivo
public interface DataSourceHasFilename extends DataSource {
String getDbFilename();
}
// classe que tem o código do proxy
public class ProxyDataSource {
private final DroidDataSource ds;
private final DataSourceHasFilename dshf;
public ProxyDataSource(DroidDataSource ds) {
this.ds = ds;
String dbFilename = "/data/data/" + ds.getPackageName() + "/" + ds.getDatabaseName() + ".db";
dshf = (DataSourceHasFilename) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[] {DataSourceHasFilename.class }, (proxy, method, args) -> {
switch (method.getName()) {
case "getDbFilename":
return dbFilename;
case "getConnection":
return connWrapper((Connection) method.invoke(ds, args));
}
return method.invoke(ds, args);
});
}
public DataSourceHasFilename asDataSourceHasFilename() {
return dshf;
}
private Connection connWrapper(Connection c) {
return (Connection) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[] { Connection.class }, (proxy, method, args) -> {
switch (method.getName()) {
case "getMetaData":
return metadataWrapper((DatabaseMetaData) method.invoke(c, args));
}
return method.invoke(c, args);
});
}
public DatabaseMetaData metadataWrapper(DatabaseMetaData dmd) {
return (DatabaseMetaData) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[] { DatabaseMetaData.class }, (proxy, method, args) -> {
switch (method.getName()) {
case "getDatabaseMajorVersion":
return 3;
case "getDatabaseMinorVersion":
return 7;
}
return method.invoke(dmd, args);
});
}
}
The creation of proxy calls to java.lang.reflect.Proxy.newProxyInstance
. It creates an object with the interfaces passed in the method call newProxyInstance
and that, somehow, all calls made to the methods of that interface are delegated to the InvocationHandler
.
So, like, underneath the covers, Java creates this object?
It needs some modifier to indicate that it is proxy?
Why doesn’t he create methods bridge when implementing an interface extending a generic interface, but rather 2 distinct concrete methods*?
*: I got this by taking the interface
B
of Victor Stafusa’s reply and instantiating her as proxy:Proxy.newProxyInstance(Main.class.getClassLoader(), new Class[] { B.class }, (Object proxy, Method method, Object[] argsM) -> { switch (method.getName()) { case "getBar1": return 1; case "isOk": return true; } return null; });