Related
I have 3 files somewhat like so:
public class AConfig {
BConfig bConfig; //assume initialized
private B getA() {
return bConfig.getB(this::pickWhich);
}
public <T> Wrapper<T> pickWhich(T a, T b) {
//logic to decide whether to return a or b that doesn't actually use a or b
//store a or b in c
return new Wrapper<>(c);
}
}
.
public class BConfig {
CConfig cConfig; //assume initialized
B b1, b2; //assume initialized
public <T> B getB(BiFunction<T, T, Wrapper<T>> function) {
C c = cConfig.getC(function);
return createB(function.apply(b1, b2), c);
}
private B createB(Wrapper<B> b, C c) {
//...
}
}
.
public class CConfig {
C c1, c2; //assume initialized
public <T> C getC(BiFunction<T, T, Wrapper<T>> function) {
return createC(function.apply(c1, c2));
}
public C createC(Wrapper<C> c) {
//...
}
}
What I'm trying to do is make it so I can pass down the function and use it in both methods getB and getC, but I get errors in the apply parenthesis saying "apply (T, T) in BiFunction cannot be applied to (B, B)" and the same error in getC but with "(C, C)".
I know if I change getB to
public B getB(BiFunction<B, B, Wrapper<B>> function) {
C c = cConfig.getC(function);
return createB(function.apply(b1, b2), c);
}
It will work fine, but then I can't pass the function down through the getC call.
Is there any way to keep the function generic so it can be used in both methods?
The problem is that createB requires as an input a Wrapper<B> but the only thing that is guaranteed in the current code to have is a Wrapper<T> where T is totally unbound (can be anything).
Same with createC it would need that the input BiFunction returns a Wrapper<C>.
So the problem is whether you can construct a BiFunction that would simultaneously have a Wrapper and Wrapper return.
If T extends B and C (so is declared as <T extends B & C> This seems to
be accomplished.
However since you intent to apply the BiFunction on B and C arguments T also need to be a supper of both B and C .... so in the end T, B and C need to be the same class!!!
I think you may need to rethink your design.
public abstract class OuterClass<OT extends OuterClass<OT>> {
public <C extends OuterClass<?>> C parse(Class<C> clazz) {
if (clazz.isInstance(this)) {
return (C) this;
}
return null;
}
public abstract class InnerClass<CT extends InnerClass<CT> {
public <C extends InnerClass<?>> C parse(Class<C> clazz) {
if (clazz.isInstance(this)) {
return (C) this;
}
return null;
}
}
}
OuterClass<?> oInstance;
InnerClass<?> iInstance;
In the above example the iInstance variable works fine. However the iInstance variable shows an error when adding the generics part
Type arguments given on a raw type
If I remove the generics part from variables, then the below test cases will fail with type errors
public class ExtendedOuter extends OuterClass<ExtendedOuter> {
}
// This only works on OuterClass<?> and not on OuterClass
ExtendedOuter eInstance = oInstance.parse(ExtendedOuter.class);
Found: OuterClass, required: ExtendedOuter
This is no problem on static/outer classes as they can be defined as ClassName<?>, but non-static inner classes cannot be defined with <?>
How can I add <?> to iInstance without making InnerClass static?
EDIT:
Let me give some examples why these classes uses their extended versions as generic.
public abstract class OuterClass<OT extends OuterClass<OT>> {
public abstract OT returnMe();
}
public class ExtendedOuter extends OuterClass<ExtendedOuter> {
#Override
public ExtendedOuter returnMe() {
return this;
}
}
The above for an example would not work if I simply made the return type OuterClass on the abstract version. If so, any extended versions would have to be casted whenever this method was used, which does not seam ideal.
Also just got an error from AndroidStudio as well after removing <CT> in <T extends OuterClass<CT>>
The parameter OT is not within it's bound
This error is shown in extended classes when doing ClassName extends OuterClass<ClassName>. In other words it will not work just using <T extends OuterClass> on the abstract classes.
Similar to a previous post I did which showcased a builder patter which uses generic types and inheritance to reduce the actual code in inheritance cases, this is also possible for none-static classes. I therefore modified the builder example accordingly to avoid static inner-classes:
Parent class with parent builder:
public abstract class TestParam<Z>
{
public abstract class CommonBuilder<T extends CommonBuilder<T>>
{
protected final String a;
protected final String b;
protected final String c;
protected Z z = null;
public CommonBuilder(String a, String b, String c)
{
this.a = a;
this.b = b;
this.c = c;
}
#SuppressWarnings("unchecked")
public T withOptionalZ(Z z)
{
this.z = z;
return (T)this;
}
#SuppressWarnings("hiding")
public abstract <T> T build();
}
protected String name;
protected String a;
protected String b;
protected String c;
protected Z z = null;
protected TestParam() {
}
protected TestParam(String name, String a, String b, String c)
{
this.name = name;
this.a = a;
this.b = b;
this.c = c;
}
protected TestParam(String name, String a, String b, String c, Z z)
{
this.name = name;
this.a = a;
this.b = b;
this.c = c;
this.z = z;
}
public String getA()
{
return a;
}
public String getB()
{
return b;
}
public String getC()
{
return c;
}
protected abstract String getContent();
#Override
public String toString()
{
return name+"[A: " + a + ", B: " + b + ", C: " + c + (z != null ? ", Z: " + z.toString() : "") + getContent() +"]";
}
}
A child class with a none-static builder looks like this:
#SuppressWarnings({"hiding", "unchecked"})
public class TestParamA<D,E,Z> extends TestParam<Z>
{
public class Builder<T extends TestParamA<D,E,Z>,
B extends TestParamA<D,E,Z>.Builder<? extends TestParamA<D,E,Z>, ? extends B, D, E>,
D,E>
extends TestParam<Z>.CommonBuilder<Builder<TestParamA<D,E,Z>,B, D,E>>
{
protected D d;
protected E e;
public Builder(String a, String b, String c)
{
super(a, b, c);
}
public B withD(D d)
{
this.d = d;
return (B)this;
}
public B withE(E e)
{
this.e = e;
return (B)this;
}
#Override
public <T> T build()
{
TestParamA<D,E,Z> t = new TestParamA<>("TestParamA", a, b, c, z, d, e);
return (T)t;
}
}
protected D d;
protected E e;
public TestParamA() {
super();
}
protected TestParamA(String name, String a, String b, String c, Z z, D d, E e)
{
super(name, a, b, c, z);
this.d = d;
this.e = e;
}
public D getD()
{
return d;
}
public E getE()
{
return e;
}
#Override
protected String getContent()
{
return ", D: " + d + ", E: " + e;
}
}
To test the functionality of this outer/inner classes you can implement something like this:
public class Main
{
public static void main(String ... args)
{
TestParamA<D,E,String> a = new TestParamA<>().new Builder<>("a","b","c").withD(new D()).withE(new E()).build();
TestParamB<F,G,String> b = new TestParamB<>().new Builder<>("a","b","c").withF(new F()).withG(new G()).withOptionalZ("z").build();
TestParam<String> c = new TestParamA<>().new Builder<>("a","b","c").withD(new D()).withE(new E()).withOptionalZ("z").build();
TestParam<?> d = new TestParamB<>().new Builder<>("a","b","c").withF(new F()).withG(new G()).build();
test(a);
test(b);
test(c);
test(d);
TestParam<?>.CommonBuilder<? extends TestParam<?>.CommonBuilder<?>> builder =
new TestParamA<>().new Builder<>("a", "b", "c").withD(new D()).withE(new E());
test(builder);
// or a bit shorter
TestParam<?>.CommonBuilder<?> builder2 =
new TestParamB<>().new Builder<>("a", "b", "c").withF(new F()).withG(new G());
test(builder2);
}
public static void test(TestParamA<?,?,?> testParam)
{
System.out.println("Test for ParamA: " + testParam.toString());
}
public static void test(TestParamB<?,?,?> testParam)
{
System.out.println("Test for ParamB: " + testParam.toString());
}
public static void test(TestParam<?> testParam)
{
System.out.println("Test for Param: " + testParam.toString());
}
public static void test(TestParam<?>.CommonBuilder<?> builder)
{
System.out.println("Test for CommonBuilder: " + builder.build().toString());
}
}
TestParamB is identical to TestParamA - it only contains varialbe and builder-methods for F and G instead of D and E. Furthermore, D, E, F and G are only classes with a simple toString() implementation which returns just the simple classname.
This will print the following output:
Test for ParamA: TestParamA[A: a, B: b, C: c, D: D, E: E]
Test for ParamB: TestParamB[A: a, B: b, C: c, Z: z, F: F, G: G]
Test for Param: TestParamA[A: a, B: b, C: c, Z: z, D: D, E: E]
Test for Param: TestParamB[A: a, B: b, C: c, F: F, G: G]
Test for CommonBuilder: TestParamA[A: a, B: b, C: c, D: D, E: E]
Test for CommonBuilder: TestParamB[A: a, B: b, C: c, F: F, G: G]
However the iInstance variable shows an error when adding the generics
part
Type arguments given on a raw type
First of all, that's not the problem you should be getting, because InnerClass is not defined in the scope. Being an inner class, it is scoped inside the outer class's scope. So when it is outside the outer class, you need to explicitly qualify it with an outer class, or it will give you a InnerClass symbol not found error. So you are not showing your real code (maybe you have another InnerClass somewhere) or not show your real error.
If I remove the generics part from variables, then the below test
cases will fail with type errors
When you use a raw type to access members, that turns off all generics on those members. So .parse() is erased to public OuterClass parse(Class clazz) (this is true even though CT is not used by the method), and that's why oInstance.parse(ExtendedOuter.class) returns type OuterClass which is not compatible with ExtendedOuter.
How can I add <?> to iInstance without making InnerClass static?
Like OuterClass<?>.InnerClass<?>, or OuterClass<Something>.InnerClass<SomethingElse>
Here's an example from my code:
Baseclass:
abstract class AbstractBase implements Comparable<AbstractBase> {
private int a;
private int b;
public int compareTo(AbstractBase other) {
// compare using a and b
}
}
Implementation:
class Impl extends AbstractBase {
private int c;
public int compareTo(Impl other) {
// compare using a, b and c with c having higher impact than b in AbstractBase
}
FindBugs reports this as an issue. But why is that? What could happen?
And how would I correctly implement a solution?
Impl#compareTo(Impl) is not overriding AbstractBase#compareTo(AbstractBase) since they don't have the same signature. In other words, it won't be called when using Collections#sort for example.
EDIT: Added solution without casting
If you don't want to cast you could try the following.
Alter your baseclass to:
abstract class AbstractBase<T extends AbstractBase<?>> implements Comparable<T> {
//...
public int compareTo(T other) {
//...
}
}
And you Impl class to:
class Impl extends AbstractBase<Impl> {
//...
#Override
public int compareTo(Impl other) {
//...
}
}
Solution with casting:
A possible solution would be to override the compareTo(AbstractBase) method in the Impl class and explicitly check if an instance of Impl is passed in:
class Impl extends AbstractBase {
//...
#Override
public int compareTo(AbstractBase other) {
if (other instanceof Impl) {
int compC = Integer.compare(c, ((Impl) other).c);
if (compC == 0) {
return super.compareTo(other);
}
return compC;
}
return super.compareTo(other);
}
}
The following is something that I tried. Not exactly sure this is the reason why findbugs gives the error.
See the following code with a hypothetical implementation of the compareTo method.
Comparing the same objects results in different outputs.
public class Main
{
public static void main(String[] args)
{
Impl implAssignedToImpl = new Impl(1, 2, 3);
Impl otherImpl = new Impl(3, 2, 1);
System.out.println(implAssignedToImpl.compareTo(otherImpl)); // prints -2
AbstractBase implAssignedToAbstract = implAssignedToImpl;
System.out.println(implAssignedToAbstract.compareTo(otherImpl)); //prints 0
}
}
class AbstractBase implements Comparable<AbstractBase>
{
private int a;
private int b;
public AbstractBase(int a, int b)
{
super();
this.a = a;
this.b = b;
}
public int compareTo(AbstractBase other)
{
return (a + b) - (other.a + other.b);
}
}
class Impl extends AbstractBase
{
private int c;
public Impl(int a, int b, int c)
{
super(a, b);
this.c = c;
}
public int compareTo(Impl other)
{
return super.compareTo(other) + (c - other.c);
}
}
Building on my hypothetical compareTo, following seems to be a good solution. You can try to have a method similar to getSum which gives the object instance a value.
public class Main
{
public static void main(String[] args)
{
Impl implAssignedToImpl = new Impl(1, 2, 3);
Impl otherImpl = new Impl(3, 2, 1);
System.out.println(implAssignedToImpl.compareTo(otherImpl)); // prints 0
AbstractBase implAssignedToAbstract = implAssignedToImpl;
System.out.println(implAssignedToAbstract.compareTo(otherImpl)); //prints 0
}
}
class AbstractBase implements Comparable<AbstractBase>
{
private int a;
private int b;
public AbstractBase(int a, int b)
{
super();
this.a = a;
this.b = b;
}
public int compareTo(AbstractBase other)
{
return getSum() - other.getSum();
}
public int getSum()
{
return a + b;
}
}
class Impl extends AbstractBase
{
private int c;
public Impl(int a, int b, int c)
{
super(a, b);
this.c = c;
}
#Override
public int getSum()
{
return super.getSum() + c;
}
}
As sp00m said, your Impl#compareTo(Impl) has a different signature than AbstractBase#compareTo(AbstractBase), so it's not overloading it.
The key point is in understanding why it doesn't work, even when you try to sort() comparing with another Impl, where the more specific signature do matches.
As you defined Comparable<AbstractBase>, you need to define how your
instances compareTo AbstractBase instances. And so you need to implement compareTo(AbstractBase).
You can think that, being Impl a subtype of AbstractBase, the more specific method would be used when a comparison between two Impls takes place. The problem is Java has static binding, and so the compiler defines at compile time which method would use for solving each method call. If what you were doing was sorting AbstractBases, then the compiler would use the compareTo(AbstractBase), that is the one AbstractBase's interface define when it implements the Comparable(AbstractBase) interface.
You can make Impl implement the Comparable<Impl> interface for using the compareTo(Impl) method, but that would only work if you explicitly sort things that are known to be Impls at compile time (ie, an Impl object or Collection<Impl>).
If you really want to apply a different comparison whenever your two objects are Impls, you should fall to some kind of double-dispatch in your Impl#compareTo(AbstractBase) like:
Impl >>>
int compareTo(AbstractBase other) {
return other.compareToImpl(this);
}
int compareToImpl(Impl other) {
// perform custom comparison between Impl's
}
AbstractBase >>>
int compareTo(AbstractBase other) {
// generic comparison
}
int compareToImpl(Impl other) {
// comparison between an AbstractBase and an Impl.
//Probably could just "return this.compareTo(other);", but check for loops :)
}
This requires you add some Impl information in your AbstractBase, which is not pretty, though, but solves the problem the more elegant way it could - using reflection for this is not elegant at all.
The Liskov substitution principle (http://en.wikipedia.org/wiki/Liskov_substitution_principle) states: if S is a subtype of T, then objects of type T may be replaced with objects of type S (i.e., objects of type S may substitute objects of type T) without altering any of the desirable properties of that program (correctness, task performed, etc.)
In your case, you are overriding the compareTo method from the Base class in a way that breaks the behaviour of the original method. This is probably why FindBugs has an issue with it.
If you want to be proper about it:
abstract class AbstractBase {
}
class Impl1 extends AbstractBase implements Comparable<Impl1> ...
class Impl2 extends AbstractBase implements Comparable<Impl2> ...
OR
even better, do not use the Comparable interface at all - use a Comparator at sort time instead.
However, in real life there are situations where you need to get around it (maybe you don't have access to the source of AbstractBase, or maybe your new class is just a POC). In these special cases, I would go with the "ugly" cast solution proposed by John.
I have got started with Java Generics. in the below class, as the class is holding T, I want to have also a class which can extend T. Please help.
public class HolderUnique<T> {
private T a;
public HolderUnique(T a){
this.a = a;
}
public T getA() {
return a;
}
public void setA(T a) {
this.a = a;
}
}
Let's say you have a class S, which extends T, and you have also declared hold as a HolderUnique<T>. Let's also say you have declared sObj as type S. There is absolutely no reason why you cannot say T.setA(sObj).
I've got two methods with the same list and types of arguments and almost the same body but each of them calls another function to fetch list of elements. To be more precise:
public void method1 (int a, int b) {
//body (the same in both of methods)
List<SomeObject> list = service.getListA(int c, int d);
//rest of the body (the same in both of methods)
}
public void method2 (int a, int b) {
//body (the same in both of methods)
List<SomeObject> list = service.getListB(int c, int d, int e);
//rest of the body (the same in both of methods)
}
What is the best approach to the problem avoiding code duplication in that case? I thought about Strategy pattern, but there is a problem with difference in argument list.
UPDATE:
public void method1 (int a, int b) {
//body (the same in both of methods)
int c = some_value;
List<SomeObject> list = service.getListA(a, b, c);
//rest of the body (the same in both of methods)
}
public void method2 (int a, int b) {
//body (the same in both of methods)
int c = some_value;
int d = another_value;
List<SomeObject> list = service.getListB(a, b, c, d);
//rest of the body (the same in both of methods)
}
So some variables are local and some are passed through arguments.
Factor them out into additional methods.
public void method1 (int a, int b) {
MyClass myClass = method3(a, b);
List<SomeObject> list = service.getListA(myClass.getC(), myClass.getD());
method4(list);
}
public void method2 (int a, int b) {
MyClass myClass = method3(a, b);
List<SomeObject> list = service.getListB(myClass.getC(), myClass.getD(), myClass.getE());
method4(list);
}
public MyClass {
private final int c;
private final int d;
private final int e;
...
}
public MyClass method3(int a, int b) {
// body
return new MyClass(c, d, e)
}
public void method4(List<SomeObject> list) {
// rest of body
}
One way of avoiding code duplication in your case could be to introduce an extra parameter that is used to decide which method to retrieve the list is going to be used:
public void method (int a, int b, int method) {
//body (the same in both of methods)
List<SomeObject> list = null;
switch (method) {
case 1:
list = service.getListA(int c, int d);
break;
case 2:
list = service.getListB(int c, int d, int e);
break;
}
//rest of the body (the same in both of methods)
}
instead of using int method as the additional parameter I would use an new enum type and define a default case in the switch statement.
Encapsulate the invocation of service.getListA or service.getListB in an ListSource class/interface, implement each version in concrete classes and pass a concrete instance as a third argument. This is basically the object-oriented version of the answer proposed by jlordo.
interface ListSource {
List<SomeObject> getList(int c, int d, int e);
}
class ListSourceA implements ListSource {
// constructor etc.
#Override
public getList(int c, int d, int e) {
return service.getListB(c, d);
}
}
class ListSourceB implements ListSource {
// constructor etc.
#Override
public getList(int c, int d, int e) {
return service.getListA(c, d, e);
}
}
public void method (int a, int b, ListSource source) {
//body (the same in both of methods)
List<SomeObject> list = source.getList(int c, int d, int e);
//rest of the body (the same in both of methods)
}
public void method (int a, int b, List<SomeObject> theList) {
//body (the same in both of methods)
List<SomeObject> list = theList;
//rest of the body (the same in both of methods)
}
This to me removes ALL the code duplication, means the method NEVER has to be modified each time we want to operate on a list derived using a different method signature.
I believe you could further this if the type SomeObject is not known using generics i.e. (and I am not a java programmer so you will have to read the docs)
public void method (int a, int b, List<T> theList) {
//body (the same in both of methods)
List<T> list = theList;
//rest of the body (the same in both of methods)
}
You could also use an enum:
public void method(int a, int b, Service service) {
// body
List<SomeObject> list = service.getList(myClass);
// rest
}
public enum Service {
METHOD_1 {
#Override
public List<SomeObject> getList(MyClass myClass) {}
},
METHOD_2 {
#Override
public List<SomeObject> getList(MyClass myClass) {}
};
public abstract List<SomeObject> getList(MyClass myClass);
}
public MyClass {
private final int c;
private final int d;
private final int e;
...
}
Essentially the same as #proskor except in a different form.
If the body parts depend upon one another so you can't do as #dicarlo2's answer:
private interface GetObjects {
List<SomeObject> get();
}
public void method1(int a, int b) {
impl(a, b, new GetObjects() { public List<SomeObject> get() {
return service.getListA(c, d);
}});
}
public void method2(int a, int b) {
impl(a, b, new GetObjects() { public List<SomeObject> get() {
return service.getListB(c, d, e);
}});
}
private void impl(int a, int b, GetObjects getObjects) {
//body (the same in both of methods)
List<SomeObject> list = getObjects.get();
//rest of the body (the same in both of methods)
}
You can use an enum in place of GetObjects if you are concerned about the new, but don't mind getting the order mixed up, missing out on outer this and don't want to open this up (although it could implement an public interface).
Better syntax coming in Java SE 8, possibly. IIRC, along the lines of:
public void method1(int a, int b) {
impl(a, b, { -> service.getListA(c, d) });
}