Suppose we have following classes which we can't change:
interface Base {
void accept(Visitor visitor);
}
class Foo implements Base {
short getShortValue() {
return 1;
}
#Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
class Bar implements Base {
int getIntValue() {
return 2;
}
#Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
interface Visitor {
void visit(Foo foo);
void visit(Bar bar);
}
And we need to implement method:
int getValue(Base base)
There are many possibilities to do it with visitor using some storage object:
int useArray(Base base) {
int[] result = new int[1];
base.accept(new Visitor() {
#Override
public void visit(Foo foo) {
result[0] = foo.getShortValue();
}
#Override
public void visit(Bar bar) {
result[0] = bar.getIntValue();
}
});
return result[0];
}
int useAtomic(Base base) {
AtomicInteger result = new AtomicInteger();
base.accept(new Visitor() {
#Override
public void visit(Foo foo) {
result.set(foo.getShortValue());
}
#Override
public void visit(Bar bar) {
result.set(bar.getIntValue());
}
});
return result.intValue();
}
int useMutable(Base base) {
MutableInteger result = new MutableInteger(0);
base.accept(new Visitor() {
#Override
public void visit(Foo foo) {
result.setValue(foo.getShortValue());
}
#Override
public void visit(Bar bar) {
result.setValue(bar.getIntValue());
}
});
return result.getValue();
}
Or something perverted:
int useException(Base base) {
class GotResult extends RuntimeException {
private final int value;
public GotResult(int value) {
this.value = value;
}
}
try {
base.accept(new Visitor() {
#Override
public void visit(Foo foo) {
throw new GotResult(foo.getShortValue());
}
#Override
public void visit(Bar bar) {
throw new GotResult(bar.getIntValue());
}
});
} catch (GotResult result) {
return result.value;
}
throw new IllegalStateException();
}
Or don't use visitor at all:
int useCast(Base base) {
if (base instanceof Foo) {
return ((Foo) base).getShortValue();
}
if (base instanceof Bar) {
return ((Bar) base).getIntValue();
}
throw new IllegalStateException();
}
Are these our only options now? We have Java 8 (will have 9 soon enough) and still writing these ugly pieces of error-prone code. :)
I agree that not being able to return a value from the visitor is terrible from a safe usage point of view.
To avoid the burden of the gymnastic you demonstrated above, your best option is to create a wrapper type that expose a sane API (based on the corrected visitor pattern) so that the dirty work is done only once: when converting a Base value to that wrapper type.
Here is how you could do it:
interface BaseW {
interface Cases<X> {
X foo(Foo foo);
X bar(Bar bar);
}
<X> X match(Cases<X> cases);
//or alternatively, use a church encoding:
//<X> X match(Function<Foo, X> foo, Function<Bar, X> bar);
default Base asBase() {
return match(new Cases<Base>() {
#Override
public Base foo(Foo foo) {
return foo;
}
#Override
public Base bar(Bar bar) {
return bar;
}
});
}
static BaseW fromBase(Base base) {
return new Visitor() {
BaseW baseW;
{
base.accept(this);
}
#Override
public void visit(Foo foo) {
baseW = new BaseW() {
#Override
public <X> X match(Cases<X> cases) {
return cases.foo(foo);
}
};
}
#Override
public void visit(Bar bar) {
baseW = new BaseW() {
#Override
public <X> X match(Cases<X> cases) {
return cases.bar(bar);
}
};
}
}.baseW;
}
static int useCorrectedVisitor(Base base) {
return fromBase(base).match(new Cases<Integer>() {
#Override
public Integer foo(Foo foo) {
return (int) foo.getShortValue();
}
#Override
public Integer bar(Bar bar) {
return bar.getIntValue();
}
});
// or, if church encoding was used:
// return fromBase(base).match(
// foo -> (int) foo.getShortValue(),
// bar -> bar.getIntValue()
// );
}
}
Now (shameless plug), if you don't mind using derive4j (a jsr 269 code generator) the above can be simplified a fair bit, as well as improving syntax:
#org.derive4j.Data // <- generate an BaseWs classe that allows handling
// of the interface as an algebraic data type.
interface BaseW {
interface Cases<X> {
X foo(Foo foo);
X bar(Bar bar);
}
<X> X match(Cases<X> cases);
default Base asBase() {
return match(BaseWs.cases(f -> f, b -> b));
}
static BaseW fromBase(Base base) {
return new Visitor() {
BaseW baseW;
{
base.accept(this);
}
#Override
public void visit(Foo foo) {
baseW = BaseWs.foo(foo);
}
#Override
public void visit(Bar bar) {
baseW = BaseWs.bar(bar);
}
}.baseW;
}
static int useStructuralPatternMatching(Base base) {
return BaseWs.caseOf(fromBase(base))
.foo(foo -> (int) foo.getShortValue())
.bar(Bar::getIntValue);
}
}
Actually you can take advantage of Java's generics:
interface Visitor<T> {
T visit(Foo foo);
T visit(Bar bar);
}
interface Base {
<T> T accept(Visitor<T> visitor);
}
interface Foo extends Base {
}
interface Bar extends Base {
}
public final class VisitorExample {
static class ConcreteFoo implements Foo {
#Override
public <T> T accept(Visitor<T> visitor) {
return visitor.visit(this);
}
}
static class ConcreteBar implements Bar {
#Override
public <T> T accept(Visitor<T> visitor) {
return visitor.visit(this);
}
}
static class ClassNameExtractor implements Visitor<String> {
#Override
public String visit(Foo foo) {
return foo.getClass().getName();
}
#Override
public String visit(Bar bar) {
return bar.getClass().getName();
}
}
public static void main(String[] args) {
Visitor<String> visitor = new ClassNameExtractor();
Foo foo = new ConcreteFoo();
Bar bar = new ConcreteBar();
final String stringResultFromFoo = foo.accept(visitor);
System.out.println(stringResultFromFoo);
final String stringResultFromBar = bar.accept(visitor);
System.out.println(stringResultFromBar);
}
}
By declaring the accept() method to return <T> T, you can control the return type by using a generic vistor Visitor<T>. So you can return anything but primitive types.
The downside of this approach is that if you do not want to return anything, your concrete visitor will have to be of type Visitor<Void> and it has to have an annoying return null on the visit() methods.
You can also use a member variable in the Visitor:
class VisitorSupplier {
Integer result;
#Override
public void visit(Foo foo) {
result.set(foo.getShortValue());
}
#Override
public void visit(Bar bar) {
result.set(bar.getIntValue());
}
public Integer get() {
return result;
}
}
and use as:
VisitorSupplier visitorSupplier = new VisitorSupplier();
bar.accept(visitorSupplier);
return visitorSupplier.get();
If you can modify the classes that you visit, or maybe extend, you could add a template method like:
public <T, U extends Visitor & java.util.function.Supplier<T>> T acceptSupplier(
final #NotNull U visitorSupplier
)
{
accept(visitorSupplier);
return visitorSupplier.get();
}
make your visitor to implement Supplier (with the get method that I already provided):
class VisitorSupplier implements java.util.function.Supplier<Integer> { ...
and use more elegantly as:
return bar.acceptSupplier(new VisitorSupplier());
If instead of generic names, based on patterns, you use something more business specific, you can get quite readable code like:
Statistics getStatistics() {
return data.transform(new StatisticsSupplier());
}
Related
I have some generated code (i.e. it cannot be changed) that looks something like this.
class Generated1 {
public String getA() {
return "1";
}
public void setB(String b) {
}
public void setC(String c) {
}
public void setD(String d) {
}
}
class Generated2 {
public String getA() {
return "2";
}
public void setB(String b) {
}
public void setC(String c) {
}
public void setD(String d) {
}
}
I am exploring these objects by reflection. None of them implement any common interface but there's many of them and I want to treat them as if they implement:
interface CommonInterface {
String getA();
void setB(String b);
void setC(String c);
void setD(String d);
}
It certainly should be possible. This is considered perfectly good code
class CommonInterface1 extends Generated1 implements CommonInterface {
// These are perfectly good classes.
}
class CommonInterface2 extends Generated2 implements CommonInterface {
// These are perfectly good classes.
}
I suppose what I'm looking for is something like:
private void doCommon(CommonInterface c) {
String a = c.getA();
c.setB(a);
c.setC(a);
c.setD(a);
}
private void test() {
// Simulate getting by reflection.
List<Object> objects = Arrays.asList(new Generated1(), new Generated2());
for (Object object : objects) {
// What is the simplest way to call `doCommon` with object here?
doCommon(object);
}
}
My question: How do I treat an object that doesn't implement an interface but actually has all the code to do so as if it does implement the interface.
I want to replace
private void doCommon(Generated1 c) {
String a = c.getA();
c.setB(a);
c.setC(a);
c.setD(a);
}
private void doCommon(Generated2 c) {
String a = c.getA();
c.setB(a);
c.setC(a);
c.setD(a);
}
...
with
private void doCommon(CommonInterface c) {
String a = c.getA();
c.setB(a);
c.setC(a);
c.setD(a);
}
I know I can use a Proxy like this but I'd really prefer to use something better.
private void test() {
// Simulate getting by reflection.
List<Object> objects = Arrays.asList(new Generated1(), new Generated2());
for (Object object : objects) {
// What is the simplest way to call `doCommon` with object here?
doCommon(adapt(object));
}
}
private CommonInterface adapt(Object o) {
return adapt(o, CommonInterface.class);
}
public static <T> T adapt(final Object adaptee,
final Class<T>... interfaceToImplement) {
return (T) Proxy.newProxyInstance(
adaptee.getClass().getClassLoader(),
interfaceToImplement,
// Call the equivalent method from the adaptee.
(proxy, method, args) -> adaptee.getClass()
.getMethod(method.getName(), method.getParameterTypes())
.invoke(adaptee, args));
}
If you're using reflection, you don't need the two CommonInterfaceX classes, you can use a proxy implementing CommonInterface:
public class Wrapper implements InvocationHandler {
private final Object delegate;
public static <T> T wrap(Object obj, Class<T> intf) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Object proxy = Proxy.newProxyInstance(cl, new Class<?>[] {intf},
new Wrapper(obj));
return intf.cast(proxy);
}
private Wrapper(Object delegate) {
this.delegate = delegate;
}
#Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Method dmethod = delegate.getClass().getMethod(
method.getName(), method.getParameterTypes());
return dmethod.invoke(delegate, args);
}
}
You can use this class as follows:
List<Object> objects = Arrays.asList(new Generated1(), new Generated2());
for (Object object : objects) {
CommonInterface proxy = Wrapper.wrap(object, CommonInterface.class);
doCommon(proxy);
}
UPDATE: note that the same Wrapper class works with any interface.
There's no way to achieve a static type relationship between Generated1 and Generated2.
Even if you created CommonInterface1 and CommonInterface2, you still wouldn't be able to statically use a Generated1 object as a CommonInterface1 because new Generated1() is not a CommonInterface1 (and will never become one)
By far the simplest solution is to change your code generation to add the CommonInterface to Generated1 and Generated2.
If that's absolutely impossible, the only other way to avoid this code duplication is to go for reflection.
You can do it manuallly by reflection.
public class Generated {
public String getA() {
return "A";
}
public String sayHello(String name) {
return "hello " + name;
}
}
public class Helper {
private static final String METHOD_NAME = "getA";
private static final String METHOD_WITH_PARAM_NAME = "sayHello";
public static void main(String[] args) throws Exception {
Generated generated = new Generated();
accessMethod(generated);
accessMethodWithParameter(generated);
}
private static void accessMethod(Generated g) throws Exception {
Method[] methods = g.getClass().getDeclaredMethods();
for(Method method : methods) {
if(isCommonMethod(method)) {
String result = (String) method.invoke(g);
System.out.println(METHOD_NAME + "() = " + result);
}
}
}
private static boolean isCommonMethod(Method m) {
return m.getName().equals(METHOD_NAME) && m.getReturnType().equals(String.class);
}
private static void accessMethodWithParameter(Generated g) throws Exception {
Method[] methods = g.getClass().getDeclaredMethods();
for(Method method : methods) {
if(isCommonMethodWithParameter(method)) {
String result = (String) method.invoke(g, "Max");
System.out.println(METHOD_WITH_PARAM_NAME + "(\"Max\") = " + result);
}
}
}
private static boolean isCommonMethodWithParameter(Method m) {
return m.getName().equals(METHOD_WITH_PARAM_NAME) &&
m.getReturnType().equals(String.class) &&
m.getParameterTypes().length == 1 &&
m.getParameterTypes()[0].equals(String.class);
}
}
Output is
getA() = A
sayHello("Max") = hello Max
If you want to replace as your comment. I think you can do it easily
First, you create interface CommonInterface
interface CommonInterface {
String getA();
void setB(String b);
void setC(String c);
void setD(String d);
}
After that, you create 2 class Generated1 and Generated2 inherited CommonInterface
class Generated1 implements CommonInterface {
#overide
public String getA() {
return "1";
}
#overide
public void setB(String b) {
}
#overide
public void setC(String c) {
}
#overide
public void setD(String d) {
}
}
class Generated2 implements CommonInterface {
#overide
public String getA() {
return "2";
}
#overide
public void setB(String b) {
}
#overide
public void setC(String c) {
}
#overide
public void setD(String d) {
}
}
I have a method that returns a class type, and it is working right.
The problem is... I am getting some compilation warnings indicating unchecked conversion.
Below is the warning message I got:
Warning: java: getAjaxEventPayloadClass() in <anonymous com.iyotbihagay.wicket.panel.requestpage.resultlist.ResultList2$7> implements <P>getAjaxEventPayloadClass() in com.iyotbihagay.wicket.panel.paging.Paging.Support
return type requires unchecked conversion from java.lang.Class<com.iyotbihagay.wicket.support.RefreshSearchResultEventPayload> to java.lang.Class<P>
even if I use #SuppressWarnings("unchecked") I still cannot get rid of the compilation warning.
Below are some of the codes pointing to the warning:
ResultList2.java
public class ResultList2 {
...
private Component createPaging() {
return new Paging("paging", getRequestPageContext(), new Paging.Support() {
#Override
public void switchPage(AjaxRequestTarget target, int targetPageNum) {
getRequestPageContext().switchPage(target, targetPageNum);
}
#Override
public int getTotalNum() {
return getSearchResult().getTotalNum();
}
#Override
public int getPageSize() {
return getSearchResult().getPageSize();
}
#Override
public int getLastPageNum() {
return getSearchResult().getLastPageNum();
}
#Override
public int getCurrentPageNum() {
return getSearchResult().getCurrentPageNum();
}
#SuppressWarnings("unchecked")
#Override
public Class<RefreshSearchResultEventPayload> getAjaxEventPayloadClass() {
return RefreshSearchResultEventPayload.class;
}
#Override
public void decorateAjaxAttributes(AjaxRequestAttributes attributes, String pageNumMarkupId) {
decorateAjaxRefreshSearchResult(attributes, pageNumMarkupId);
}
});
}
...
}
Support.java
public static interface Support extends Serializable {
...
<P extends AjaxEventPayload> Class<P> getAjaxEventPayloadClass();
...
}
Paging.java
public class Paging {
...
private Support m_support;
...
#Override
public void onEvent(IEvent<?> event) {
super.onEvent(event);
WicketUtil.onEvent(event, m_support.getAjaxEventPayloadClass(), new AjaxEventHandler<AjaxEventPayload>() {
#Override
public void onEvent(IEvent<?> event, AjaxRequestTarget target, AjaxEventPayload paymentLoad) {
m_firstPageNumModel.detach();
m_previousPageNumModel.detach();
m_nextPageNumModel.detach();
m_lastPageNumModel.detach();
target.add(m_container);
}
});
}
...
}
WicketUtil.java
public class WicketUtil {
...
public static <P extends AjaxEventPayload> void onEvent(IEvent<?> event, Class<P> targetPayload, AjaxEventHandler<P> handler) {
if (event.getPayload() != null) {
if (targetPayload.isAssignableFrom(event.getPayload().getClass())) {
P p = (AjaxEventPayload)event.getPayload();
handler.onEvent(event, p.getTarget(), p);
}
}
}
...
}
m_support.getAjaxEventPayloadClass() is called/passed on WicketUtil.onEvent()... specifically on the second parameter.
RefreshSearchResultEventPayload is just one of the classes that extends AjaxEventPayload and there are other classes that extends to AjaxEventPayloadand are passed to WicketUtil.onEvent().
This should rather be:
public static interface Support extends Serializable {
...
Class<? extends AjaxEventPayload> getAjaxEventPayloadClass();
...
}
and
public class ResultList2 {
...
#Override
public Class<RefreshSearchResultEventPayload> getAjaxEventPayloadClass() {
return RefreshSearchResultEventPayload.class;
}
...
}
The reason is that <P extends AjaxEventPayload> means that the method can return a class of arbitrary payload type (as requested by the caller), e.g.:
support.<AjaxEventPayload>getAjaxEventPayloadClass()
instead of returning only the one payload type that is specific to the implementing class (e.g. RefreshSearchResultEventPayload).
So, after this question where I basically exploits reflection for passing primitive references to modify the primitive itself, like:
_begin("Another Window", ::showAnotherWindow)
I was looking for something to make something similar possible also from java, where at the moment I am using plains primitive arrays:
private boolean[] showAnotherWindow = {false};
imgui.begin("Another Window", showAnotherWindow);
#hotkey suggested me the possibility to create a class implementing the KMutableProperty0 interface and that automatically gets and sets the corresponding variable
Example:
KMutableProperty0<Boolean> prop =
PropUtils.javaProp(this, t -> t.showAnotherWindow, (t, r) -> { t.showAnotherWindow = r; });
_begin("Another Window", prop);
So, I wanted to give it a try and implemented the following in java.
Getter:
#FunctionalInterface
public interface Getter<T> {
T get();
}
Setter:
#FunctionalInterface
public interface Setter<T> {
void set(T type);
}
And then the class itself (I just wrote the constructor, all the methods are those requested by the interface and automatically implemented by the IDE) :
public class JavaProp <T> implements KMutableProperty0<T> {
private imgui.Getter<T> getter;
private imgui.Setter<T> setter;
public JavaProp(imgui.Getter<T> getter, imgui.Setter<T> setter) {
this.getter = getter;
this.setter = setter;
}
#Override
public void set(T t) {
setter.set(t);
}
#NotNull
#Override
public Setter<T> getSetter() {
return null;
}
#Override
public T get() {
return getter.get();
}
#Nullable
#Override
public Object getDelegate() {
return null;
}
#NotNull
#Override
public Getter<T> getGetter() {
return null;
}
#Override
public T invoke() {
return null;
}
#Override
public boolean isLateinit() {
return false;
}
#Override
public boolean isConst() {
return false;
}
#NotNull
#Override
public String getName() {
return null;
}
#NotNull
#Override
public List<KParameter> getParameters() {
return null;
}
#NotNull
#Override
public KType getReturnType() {
return null;
}
#NotNull
#Override
public List<KTypeParameter> getTypeParameters() {
return null;
}
#Override
public T call(Object... objects) {
return null;
}
#Override
public T callBy(Map<KParameter, ?> map) {
return null;
}
#Nullable
#Override
public KVisibility getVisibility() {
return null;
}
#Override
public boolean isFinal() {
return false;
}
#Override
public boolean isOpen() {
return false;
}
#Override
public boolean isAbstract() {
return false;
}
#NotNull
#Override
public List<Annotation> getAnnotations() {
return null;
}
}
But whenever I try to run that, I get the following:
Error:(45, 12) java: reference to Getter is ambiguous
both interface kotlin.reflect.KProperty0.Getter in kotlin.reflect.KProperty0 and interface kotlin.reflect.KProperty.Getter in kotlin.reflect.KProperty match
The problematic function is this one:
#NotNull
#Override
public Getter<T> getGetter() {
return null;
}
And the relevant file is kotlin.reflect.KProperty.tk, you can find it here
Any idea how could I solve it?
Just specify which interface you mean:
public KProperty0.Getter<T> getGetter()
But I would prefer to implement the class in Kotlin and only consume it from Java.
SSCCE:
public class Test {
public Test() {
new Anonymous1() {
void validate() {
new Anonymous2() {
int calculate() {
return Math.abs(Anonymous1.this.getValue()); // compilation error - Anonymous1 is not an enclosing class
}
};
}
};
}
}
abstract class Anonymous1 {
abstract void validate();
int getValue() {
return 0;
}
}
abstract class Anonymous2 {
abstract int calculate();
}
I know that it looks complicated and unusable, but I am just wonder is it possible to point to Anonymous1 class from Anonymous2 using .this pointer, or in any else way.
You need to do it in the class.
public Test() {
new Anonymous1() {
void validate() {
final Object this1 = this;
new Anonymous2() {
int calculate() {
return Math.abs(this1.getValue());
}
}
}
}
}
or even better, extract the things you need first and use effectively final added in Java 8.
public Test() {
new Anonymous1() {
void validate() {
int value = getValue();
new Anonymous2() {
int calculate() {
return Math.abs(value);
}
}
}
}
}
if Anonymous1 and Anonymous2 were interfaces you could use lambdas in Java 8.
public Test() {
Anonymous1 a = () -> {
int v = getValue();
Anonymous2 = a2 = () -> Math.abs(v);
};
}
What is the simplest and workable implementation of the interface of M. And how to implement method flatMap?
public interface M<T> {
<U> M<U> flatMap(Function<T, M<U>> f);
M<T> unit(T t);
}
I'm stuck in flatMap implementation.
M<String> m = new M<String>() {
#Override
public <U> M<U> flatMap(Function<String, M<U>> f) {
return null; // ?
}
#Override
public M<String> unit(String s) {
return new M<String>() {
#Override
public <U> M<U> flatMap(Function<String, M<U>> f) {
return null; // ?
}
#Override
public M<String> unit(String s) {
return null; // ?
}
};
}
};