I have the following code
public class A {
public class B {
}
public boolean wasCreatedFromMe(B obj) {
// I want to implement this method
}
}
public class Test {
public static void main(String[] args) {
A a1 = new A();
A a2 = new A();
B b1 = a1.new B();
a1.wasCreatedFromMe(b1); // true
a2.wasCreatedFromMe(b1); // false
}
}
I would like to implement that method above which determines if the object was created from this Outer Class instance. Is there a way to use instanceof or some type of Class<> magic to do that?
I do NOT want to do any of the following:
Use data structures
// inside class A
Set<B> childObjs = new HashSet<>();
public B() {
childObjs.add(this);
}
Ask inner class object
// inside class A
public boolean wasCreatedFromMe(B obj) {
return obj.parent() == this;
}
class B {
public A parent() {
return A.this;
}
}
I'm using an external library that provides tightly related classes (generated from some template), but unfortunately without a shared interface, e.g.
public class A {
public UUID id();
public Long version();
public String foo();
public String bar();
}
public class B {
public UUID id();
public Long version();
public String foo();
public String bar();
}
public class C {
public UUID id();
public Long version();
public String foo();
public String bar();
}
// ... and more: D, E, F, etc.
Given I have no influence over the external library, what's the idiomatic way to write logic common to a group of classes that share the same method signatures (at least, for the methods being used by the common logic)?
Currently I do one of three things, on a case-by-case basis:
I write helper methods that take the primitive results from each object, e.g.
private static void myHelper(UUID id, Long version, String foo, String bar) {
...
}
This way I can "unpack" an object regardless of its type:
myHelper(whatever.id(), whatever.version(), whatever.foo(), whatever.bar());
But that can get very wordy, especially when I need to work with many members.
In the scenario where I'm only working with getters (i.e. only need to access current values of the objects), I've found a way to use mapping libraries like Dozer or ModelMapper to map A or B or C to my own common class, e.g.
public class CommonABC {
UUID id;
Long version;
String foo;
String bar;
}
By playing with configuration, you can get these libraries to map all members, whether method or field, public or private, to your class, e.g.
modelMapper.getConfiguration()
.setFieldMatchingEnabled(true)
.setFieldAccessLevel(Configuration.AccessLevel.PRIVATE);
But this was kind of a "broadsword" approach, a hack that IMO isn't clearly justified merely to factor out duplicate code.
Finally, in certain other scenarios it was most succinct to simply do
private static void myHelper(Object extLibEntity) {
if (extLibEntity instanceof A) {
...
} else if (extLibEntity instanceof B) {
...
} else if (extLibEntity instanceof C) {
...
} else {
throw new RuntimeException(...);
}
}
It's obvious why this is bad.
In enterprise situations where you have to live with a library that is this way, what would you do?
I'm leaning toward writing a very explicit, if verbose, mapper (not using a generic mapper library) that translates these entities from the start. But, I wonder if there's a better way. (Like, is there a way to "cast" an object as implementing a new interface, in runtime?)
An option that is (under the hood) likely similar to the second approach, but comparatively lean and flexible, is to use Dynamic Proxy Classes. With only a few lines of code, you can let any object "appear" to implement a certain interface, as long as it has the required methods. The following is an MCVE that shows the basic approach:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.UUID;
public class DelegatingProxyExample {
public static void main(String[] args) {
A a = new A();
B b = new B();
C c = new C();
CommonInterface commonA = wrap(a);
CommonInterface commonB = wrap(b);
CommonInterface commonC = wrap(c);
use(commonA);
use(commonB);
use(commonC);
}
private static void use(CommonInterface commonInterface) {
System.out.println(commonInterface.id());
System.out.println(commonInterface.version());
System.out.println(commonInterface.foo());
System.out.println(commonInterface.bar());
}
private static CommonInterface wrap(Object object) {
CommonInterface commonInterface = (CommonInterface) Proxy.newProxyInstance(
CommonInterface.class.getClassLoader(),
new Class[] { CommonInterface.class }, new Delegator(object));
return commonInterface;
}
}
// Partially based on the example from
// https://docs.oracle.com/javase/8/docs/technotes/guides/reflection/proxy.html
class Delegator implements InvocationHandler {
private static Method hashCodeMethod;
private static Method equalsMethod;
private static Method toStringMethod;
static {
try {
hashCodeMethod = Object.class.getMethod("hashCode", (Class<?>[]) null);
equalsMethod = Object.class.getMethod("equals", new Class[] { Object.class });
toStringMethod = Object.class.getMethod("toString", (Class<?>[]) null);
} catch (NoSuchMethodException e) {
throw new NoSuchMethodError(e.getMessage());
}
}
private Object delegate;
public Delegator(Object delegate) {
this.delegate = delegate;
}
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
Class<?> declaringClass = m.getDeclaringClass();
if (declaringClass == Object.class) {
if (m.equals(hashCodeMethod)) {
return proxyHashCode(proxy);
} else if (m.equals(equalsMethod)) {
return proxyEquals(proxy, args[0]);
} else if (m.equals(toStringMethod)) {
return proxyToString(proxy);
} else {
throw new InternalError("unexpected Object method dispatched: " + m);
}
} else {
// TODO Here, the magic happens. Add some sensible error checks here!
Method delegateMethod = delegate.getClass().getDeclaredMethod(
m.getName(), m.getParameterTypes());
return delegateMethod.invoke(delegate, args);
}
}
protected Integer proxyHashCode(Object proxy) {
return new Integer(System.identityHashCode(proxy));
}
protected Boolean proxyEquals(Object proxy, Object other) {
return (proxy == other ? Boolean.TRUE : Boolean.FALSE);
}
protected String proxyToString(Object proxy) {
return proxy.getClass().getName() + '#' + Integer.toHexString(proxy.hashCode());
}
}
interface CommonInterface {
UUID id();
Long version();
String foo();
String bar();
}
class A {
public UUID id() {
return UUID.randomUUID();
}
public Long version() {
return 1L;
}
public String foo() {
return "fooA";
}
public String bar() {
return "barA";
}
}
class B {
public UUID id() {
return UUID.randomUUID();
}
public Long version() {
return 2L;
}
public String foo() {
return "fooB";
}
public String bar() {
return "barB";
}
}
class C {
public UUID id() {
return UUID.randomUUID();
}
public Long version() {
return 3L;
}
public String foo() {
return "fooC";
}
public String bar() {
return "barC";
}
}
Of course, this uses reflection internally, and should only be used when you know what you're doing. Particularly, you should add some sensible error checking, at the place that is marked with TODO: There, the method of the interface is looked up in the given delegate object.
The only technique not tried:
package aplus;
public interface Common {
...
}
public class A extends original.A implements Common {
}
public class B extends original.B implements Common {
}
Say I have a class Foo.java and a class Bar.java. They are in the same package.
Say Foo.java looks like this:
public class Foo {
public Foo () {
//insert awt graphics shape here
}
}
And Bar.java looks like this:
public class Bar {
public Bar () {
//filler
}
}
For Bar.java, would there be any way to access the shape created in Foo.java?
The answer to your question is yes, you can. You probably can accomplish this through composition. For instance:
public class Foo {
private Bar bar = new Bar();
public Foo () {
this.bar.getSomeVal();
}
}
public class Bar {
private int someVal;
public Bar () {
this.someVal = 10;
}
public int getSomeVal() { // this is just an example method.
return this.someVal;
}
}
As you can see above, the Foo class contains an instance of the Bar class. Using that instance I can access in the Foo's constructor the members of the Bar class.
You can follow the same approach in the Bar class by having an instance of the Foo class.
You also have the option to use static methods, for instance:
public class Foo {
public Foo () {
System.out.println(Bar.getSomeVal());
}
}
public class Bar {
private static int someVal;
public Bar () {
}
public stating int getSomeVal() { // this is just an example static method.
return Bar.someVal;
}
}
if the element/functions are static :
public class foo {
static int fooElement = 0;
static void bar () {
//insert awt graphics shape here
}
static void accessBarElementNFunction() {
bar.barElement = 1;
bar.foo();
}
}
public class bar {
static int barElement = 0;
static void foo () {
//filler
}
static void accessFooElementNFunction() {
foo.fooElement = 1;
foo.bar();
}
}
otherwise, you need to create and manage the class instances.
I have written below code, just to play with interface, Would you
please tell where I have gone wrong here?
This is my interface:
package com.home.intetest;
public interface IFoo {
public abstract String doWork(String str) throws Exception;
}
This is where I have implemented,
package com.home.intetest;
public class FooImpl implements IFoo {
#Override
public String doWork(String str) throws Exception {
if(str !=null) {
System.out.println(str);
}else{
System.out.println("Wrongggg");
}
return str;
}
}
Now I am trying to call them from main, using getter method, its giving me error,in line where I am using getiFoo method
package com.home.intetest;
public class TestMain {
private IFoo iFoo;
public IFoo getiFoo() {
return iFoo;
}
public void setiFoo(IFoo iFoo) {
this.iFoo = iFoo;
}
public static void main(String[] args) {
String str = "Work method";
callWorkMethod(str);
}
private static void callWorkMethod(String str) {
String s = getiFoo().doWork(str);
}
}
1
The line
getiFoo().doWork(str);
can not be called, you need a instance of TestMail first! So boot-up your Application like this:
new TestMain().getiFoo().doWork(str);
2
The error you recieve is a NullPointerException now because iFoo is always null.
Create a instance in the getter using the default constructor like this:
public IFoo getiFoo() {
if (iFoo == null) {
iFoo = new FooImpl();
}
return iFoo;
}
Or inside the declaration like this:
private IFoo iFoo = new FooImpl();
I'm using the Apache Commons EqualsBuilder to build the equals method for a non-static Java inner class. For example:
import org.apache.commons.lang.builder.EqualsBuilder;
public class Foo {
public class Bar {
private Bar() {}
public Foo getMyFoo() {
return Foo.this
}
private int myInt = 0;
public boolean equals(Object o) {
if (o == null || o.getClass() != getClass) return false;
Bar other = (Bar) o;
return new EqualsBuilder()
.append(getMyFoo(), other.getMyFoo())
.append(myInt, other.myInt)
.isEquals();
}
}
public Bar createBar(...) {
//sensible implementation
}
public Bar createOtherBar(...) {
//another implementation
}
public boolean equals(Object o) {
//sensible equals implementation
}
}
Is there syntax by which I can refer to other's Foo reference apart from declaring the getMyFoo() method? Something like other.Foo.this (which doesn't work)?
No.
The best way is probably what you suggested: add a getFoo() method to your inner class.
No, not possible without a getter. The 'this' keyword will always point to the current instance. I'm quite curious why you would want to do this... seems like you are doing composition in the wrong way.
public class Foo {
public Bar createBar(){
Bar bar = new Bar(this)
return bar;
}
}
public class Bar {
Foo foo;
public Bar(Foo foo){
this.foo = foo;
}
public boolean equals(Object other) {
return foo.equals(other.foo);
}
}
Since using Foo.this limits creation of the inner class (Foo myFoo = new Foo(); myFoo.new Bar(); to an instance I'd say this is much cleaner.
yes:
public class Foo {
public class Bar {
public Foo getMyFoo() {
return Foo.this;
}
}
public Foo foo(Bar bar) {
return bar.getMyFoo();
}
public static void main(String[] arguments) {
Foo foo1=new Foo();
Bar bar1=foo1.new Bar();
Foo foo=(new Foo()).foo(bar1);
System.out.println(foo==foo1);
}
}