Java: Generic class with generic method - java

i am writing a integration test framework for my java application and i run into one issue i am not able to fix. Please let me explain:
The following code snippets are simplified classes for better visibility:
I got the following abstract class:
public abstract class AbstractTestModel<T extends AbstractTestModel> {
public T doSomething(){
return getThis();
}
public T getThis(){
return (T) this;
}
public <U extends AbstractTestModel<T>> U as(Class<U> type){
AbstractTestModel<T> obj = this;
if (obj.getClass().isAssignableFrom(type)){
return type.cast(obj);
}else{
throw new AssertionError("This (" + obj.getClass().getName() +")could not be resolved to the expected class " + type.getName());
}
}
}
And there are may concrete classes like this:
public class ConcreteTestModel1 extends AbstractTestModel<ConcreteTestModel1> {
public void doSomethingElse(){
}
}
I also wrote a Factory class. This factory downloads a JSON object from the server and instantiates one of the concret classes - depending on the JSON response. This concrete classes have many helper methods for testing the JSON response. The thing is, that the factory method always returns an "AbstractTestModel".
The integration test looks like this (simplified):
public class SomeTest {
TestModelFactory testModelFactory;
#Before
public void init(){
testModelFactory = new TestModelFactory();
}
#Test
public void someTest(){
AbstractTestModel anyModel = testModelFactory.createModel("someIdOfTheServer");
//ERROR: this does not work! Cannot resolve method doSomethingElse():
anyModel.doSomething().as(ConcreteTestModel1.class).doSomethingElse();
//as() method returns AbstractTestModel instead of ConcreteTestModel1
//this works:
AbstractTestModel as = anyModel.as(ConcreteTestModel1.class);
//this does not work:
ConcreteTestModel1 asConcreteTestModel1 = anyModel.as(ConcreteTestModel1.class);
}
}
The method as(Class type) should check if the given class is valid, cast "this" to the desired class and return it, but it always returns the AbstractTestModel.
If I make the "as" method static or if i get rid of the generic class like this...
public abstract class AbstractTestModel {
/*
Not possible to return the superclass anymore
public T doSomething(){
return getThis();
}
public T getThis(){
return (T) this;
}
*/
public <U extends AbstractTestModel> U as(Class<U> type){
AbstractTestModel obj = this;
if (obj.getClass().isAssignableFrom(type)){
return type.cast(obj);
}else{
throw new AssertionError("This (" + obj.getClass().getName() +")could not be resolved to the expected class " + type.getName());
}
}
}
... then it works fine, but of course i am not able to return the concrete class in all other methods any more.
Thank you for reading this long post.
Do you know what am i doing wrong here? Is there a solution for that?
Thank you for any tip and have a nice day!
Manuel

The problem is the compiler needs to infer the type at compile time. This code is mostly as provided, but I added some output in doSomethingElse for the sake of demonstration, and added ConcreteTestModelX extending ConcreteTestModel1 (Note I removed the type T from the as method to explore the way it interacted with generic typing in further exploratory testing).
public abstract class AbstractTestModel<T extends AbstractTestModel> {
public T doSomething() {
return getThis();
}
public T getThis() {
return (T) this;
}
public <U extends AbstractTestModel> U as(Class<U> type) {
if (getClass().isAssignableFrom(type)) {
return type.cast(this);
} else {
throw new AssertionError("This (" + getClass().getName()
+ ") could not be resolved to the expected class " + type.getName());
}
}
}
class ConcreteTestModel1 extends AbstractTestModel<ConcreteTestModel1> {
public void doSomethingElse() {
System.out.println("This is \"" + getClass().getSimpleName() + "\" doing something else");
}
}
class ConcreteTestModelX extends ConcreteTestModel1 {
}
And with this test
import org.junit.Test;
public class SomeTest {
#Test
public void someTest(){
AbstractTestModel<ConcreteTestModel1> anyModel = new ConcreteTestModel1();
ConcreteTestModel1 asConcreteTestModel1 = anyModel.as(ConcreteTestModel1.class);
asConcreteTestModel1.doSomethingElse();
AbstractTestModel anyModelX = new ConcreteTestModelX();
ConcreteTestModel1 asConcreteTestModelX = (ConcreteTestModel1)anyModelX;
asConcreteTestModelX.doSomethingElse();
}
}
Seems the problem you are having in the tests is that the variable you are using for the model is without generics, the compiler then strips the generics see this answer https://stackoverflow.com/a/18277337/7421645
Based on this I then created some new tests to explore:
import org.junit.Test;
public class SomeTest {
#Test
public void concreteTest(){
ConcreteTestModel1 asConcreteTestModel1 = getConcreteModel(new ConcreteTestModel1(), ConcreteTestModel1.class);
asConcreteTestModel1.doSomethingElse();
}
#Test
public void concreteExtendsTest(){
ConcreteTestModel1 asConcreteTestModelX = getConcreteModel(new ConcreteTestModelX(), ConcreteTestModelX.class);
asConcreteTestModelX.doSomethingElse();
}
private <T extends ConcreteTestModel1> T getConcreteModel(T anyModel, Class<T> classType) {
return anyModel.as(classType);
}
#Test
public void vanillaCastingTest(){
AbstractTestModel anyModelX = new ConcreteTestModelX();
ConcreteTestModel1 asConcreteTestModelX = (ConcreteTestModel1)anyModelX;
asConcreteTestModelX.doSomethingElse();
}
#Test
public void abstractGenericTest(){
AbstractTestModel<ConcreteTestModel1> anyModel = new ConcreteTestModel1();
ConcreteTestModel1 asConcreteTestModel1 = anyModel.as(ConcreteTestModel1.class);
asConcreteTestModel1.doSomethingElse();
}
#Test
public void failedGenericTest(){
AbstractTestModel anyModel = new ConcreteTestModel1();
ConcreteTestModel1 asConcreteTestModel1 = getAs(anyModel);
asConcreteTestModel1.doSomethingElse();
}
private ConcreteTestModel1 getAs(AbstractTestModel<ConcreteTestModel1> anyModel) {
return anyModel.as(ConcreteTestModel1.class);
}
}

Thanks to all answers, i could finally find the problem. It was actually quite easy:
The factory needed to return "AbstractTestModel<❓>" instead of just "AbstractTestModel". I've added the <❓> to every method who's returning the AbstractTestModel. Now it works just fine :) Thanks everyone. Couldn't find the answer without you.

Related

how can I add additional implementation to an overriding subclass method while still calling superclass method

I would like to add additional implementation to an overriding subclass method without completely overriding the superclass one. This is what I got to so far, but it doesn't seem to work. I would like the output to be "superclass return" followed by "subclass return". Here's the code:
public class A {
public String send() {
return "superclass return";
}
}
public class B extends A{
public String send() {
super.send();
return "subclass return";
}
}
public class Driver {
public static void main(String[] args) {
B b = new B();
System.out.println(b.send());
}
}
Output: subclass return
Am I using the wrong syntax super.send()? The intended output should be:
superclass return
subclass return
You have lost the return value of the super send() method and that is why you cannot see it in the output. To be able to see both, you need to modify the child implementation to something like this:
public String send() {
String value = super.send();
return value + "subclass return";
}
You aren't doing anything with the return value of the super class. Try this:
public class A {
public String send() {
return "superclass return";
}
}
public class B extends A{
public String send() {
return super.send() + "subclass return";
}
}
public class Driver {
public static void main(String[] args) {
B b = new B();
System.out.println(b.send());
}
}
Or if you want the line break:
return super.send() + "\nsubclass return";

using object functions in java

I'm trying to implement function objects in Java. I have a Unit class, with a default addition function that should be used in most initializations of a Unit object. However, for some issues, I need a different addition function. The code will look something like this:
public class Unit() {
public Unit(unitType) {
if (unitType == "specialType") {
additionFunc = defaultFunc } else {
additionFunc = specialFunc }
}
}
public int swim() {
return additionFunc()
}
// definiion of regularFunc
// definition of specialFunc
}
Then, from the main file:
Unit fish = new Unit(regularTyoe);
Unit fatFish = new Unit(specialType);
fish.swim(); //regular function is called
fatFish.swim(); //special function is called
That's it.. does anyone know how this can be done?
You need to look up inheritance and method overriding. It would probably help to read up on proper Object Oriented Programming as well.
The proper way to do this is:
class Fish {
public void swim() {
// normal swim
}
}
class FatFish extends Fish {
#Override
public void swim() {
// special swim
}
}
Fish fish = new Fish()
Fish fatFish = new FatFish()
fish.swim() // normal swim
fatFish.swim() // slow swim
Make a new FatFish class which extends Unit and overrides swim().
Unit fish = new Unit();
Unit fatFish = new FatFish();
fish.swim(); //regular function is called
fatFish.swim(); //special function is called
There are many solutions for your problem, one of them is using inheritance, that you could have a default implementation of Unit, and extend it overriding the desired method with a new one.
Basically would be something like:
public class FatFish {
#Override
public void swim() {
// new behavior
}
}
Another approach would be to implement Strategy Design Pattern, which allows you to select algorithms on runtime. Therefore you could do something like:
public interface SwimStrategy {
void execute();
}
public class FatFishSwimStrategy implements SwimStrategy {
#Override
public void execute() {
// fat fish swim impl
}
}
public class FishSwimStrategy implements SwimStrategy {
#Override
public void execute() {
// normal fish swim impl
}
}
public class Fish {
private final SwimStrategy swimStrategy;
public Fish(SwimStrategy swimStrategy) {
this.swimStrategy = swimStrategy;
}
public void swim() {
swimStrategy.execute();
}
}
In order to instantiate an object you could do:
new Fish(new FatFishSwimStrategy());
or for the normal behavior:
new Fish(new FishSwimStrategy());
I think it can do by extends and factory method:
public class Unit {
public static Unit createUnit(UnitType type) {
if (UnitType.Special == type) {
return new Unit(type) {
#Override
public int swim() {
System.out.println("special swim");
return 0;
}
};
}
return new Unit(UnitType.Default);
}
private UnitType type;
private Unit(UnitType type) {
this.type = type;
System.out.println("create unit for " + type);
}
public int swim() {
System.out.println("default swim");
return 0;
}
public static void main(String[] args) {
Unit fish = Unit.createUnit(UnitType.Default);
Unit fatFish = Unit.createUnit(UnitType.Special);
fish.swim();
fatFish.swim();
}
}
This is a simple type enum:
public enum UnitType {
Default, Special
}
There are two ways to accomplish this polymorphic behavior in Java. The first is to use a inheritance and a hierarchical set of classes. For example, you could have an abstract base class which defines an abstract method called "swim". Then each concrete fish class would extend this base class and implement the swim method. Later when you have a set of fish objects, you can upcast them to the base class and invoke the swim method on each.
The second way is to use interfaces. You define an interface (e.g. ISwim) which declares the public method swim. Each fish class (whether part of a class hierarchy or no) would implement the ISwim interface, meaning they would define a swim method. Then if you have a set of fish class objects of different types, you can cast each to the ISwim interface and invoke the swim method on each object.
Java does not have function pointers, so the approach you are considering is inappropriate for the language. Even in languages with function pointers, the above two approaches would be most appropriate in my opinion.
One way to do this is with an enum for the types of Unit and with Unit subclasses:
public class Unit {
public enum UnitType {
REGULAR {
public Unit makeUnit() {
return new RegularUnit();
}
},
SPECIAL {
public Unit makeUnit() {
return new SpecialUnit();
}
};
abstract public Unit makeUnit();
}
protected Unit() {}
public abstract int swim();
private static class RegularUnit extends Unit {
RegularUnit() {}
public int swim() {
return 0;
}
}
private static class SpecialUnit extends Unit {
SpecialUnit() {}
public int swim() {
return 1;
}
}
}
Unit fish = UnitType.REGULAR.makeUnit();
Unit fatFish = UnitType.SPECIAL.makeUnit();
Another way is with Callable objects:
public class Unit {
public enum UnitType { REGULAR, SPECIAL }
private Callable<Integer> additionFunc;
public Unit(UnitType type) {
switch (type) {
case REGULAR:
additionFunc = new Callable<Integer>() {
public Integer call() {
return 0;
}
};
break;
case SPECIAL:
additionFunc = new Callable<Integer>() {
public Integer call() {
return 1;
}
};
break;
}
}
public int swim() {
return additionFunc();
}
}
Using a simple if statement:
private String unitType;
public Unit(unitType) {
this.unitType = unitType;
}
public int swim() {
if (unitType.equals("specialType") {
return specialFunc();
}
else {
return regularFunc();
}
}
Or using polymorphism and a factory method :
public abstract class Unit() {
protected Unit() {
}
protected abstract int addition();
public int swim() {
return addition();
}
public static Unit forType(String unitType) {
if (unitType.equals("specialType") {
return new SpecialUnit();
}
else {
return new RegularUnit();
}
}
private static class SpecialUnit extends Unit {
#Override
protected addition() {
// special addition
}
}
private static class RegularUnit extends Unit {
#Override
protected addition() {
// regular addition
}
}
}
Or using an Adder functional interface, defining an addition() method, and two concrete implementations of this interface:
private Adder adder;
public Unit(unitType) {
if (unitType.equals("specialType") {
this.adder = new SpecialAdder();
}
else {
this.adder = new RegularAdder();
}
}
public int swim() {
return adder.addition();
}
This last one is the closest to waht you asked in your question. function objects don't exist per se, but can be replaced by interfaces.

AspectJ constructor force factory pattern

I want to change the object return from call to a constuctor
FROM
public class A {
public A(){
}
public String sayHello() {
return "hello";
}
public String foo() {
return "foo";
}
}
TO
public class AWrapped extends A {
private A wrapped;
public AWrapped() {
super();
}
public AWrapped(A pWrapped) {
wrapped=pWrapped;
}
public String foo() {
return wrapped.foo();
}
public String sayHello {
return "gday mate";
}
}
What i want to do is to change the object that is returned from a call
A a = new A();
a.sayHello() returns "gday mate"
a is an instaceof AWrapped
I understand that this would usually be done with a factory pattern but I dont have access to the code of A or the code that makes new A's. And there are 1000s of places that A can be created.
It seems that Aspectj might do the trick, but i dont know much about it, If AspectJ would do the trick how to I get around the infinite wrapping i need to know that its being consturcted from within and aspect so it doesnt wrapp it again.
Thanks for the help
Jon
If I understand you right you could do the following:
I've created three packages:
aspectj for the aspect and AWrapped.java
unknown for A.java (could also be Bytecode but then you have to use Load Time Weaving)
main to test A a = new A();
MyAspect to return the AWrapped object if a new() call is made on class A:
package aspectj;
import unknown.A;
#Aspect
public class MyAspect {
#Pointcut("call(unknown.A.new(..)) && !within(aspectj..*)")
public static void init(ProceedingJoinPoint pjp) {
}
#Around("init(pjp)")
public Object initAdvice(ProceedingJoinPoint pjp) throws Throwable{
Object ret = pjp.proceed();
return new AWrapped((A) ret);
}
}
For testing:
package main;
import unknown.A;
public class Main {
public static void main(String[] args) {
A a = new A();
System.out.println(a.sayHello());
}
}
This outputs:
gday mate

Is it possible to have an enum that contains constructors for objects?

I'm testing out a different sort of pattern. I've already got the code working in a switch statement, but I'd like to try something a little more ecclectic... for research purposes.
Say I have 4 classes, Class1, Class2, Class3, and Class4 that all extend BaseClass. I want to put them into an enum, like so:
enum ClassFactories {
Class1(Class1.class),
Class2(Class2.class),
Class3(Class3.class),
Class4(Class4.class);
private final Class factory;
ClassFactories(Class factory) {
this.factory = factory;
}
public BaseClass generate() {
BaseClass b = null;
try {
b = (BaseClass)this.factory.newInstance();
} catch (Exception e) {
// handle any exceptions
}
return f;
}
}
In a factory method that is passed an int, I want to be able to do something like this:
public void fakeMethod(int type) {
BaseClass someClass = ClassFactories.values()[type].generate();
someClass.doStuff();
}
Is there a cleaner/easier way of doing this? I'm not so much concerned with readability (right now), I'm just curious if this is possible.
Yes, this is possible. Something like a 'Template Method' approach. So for example
public enum ClassFactory {
Class1() {
#Override public void generate() {
System.out.println("I'm in Class 1.");
}
},
Class2() {
#Override public void generate() {
System.out.println("I'm in Class 2.");
}
};
//template method
public abstract void generate();
private static final Map<Integer, ClassFactory > lookup
= new HashMap<Integer, ClassFactory >();
static {
for (ClassFactory s : EnumSet.allOf(ClassFactory.class))
lookup.put(s.getIntValue(), s);
}
public static ClassFactory getValue(int intValue) {
return lookup.get(intValue);
}
}
INVOCATION CODE
With the use of static imports, the client code calling this enumeration would look like:
Class1.generate();
Class2.generate();
//or better...
getClass().generate();
Or
public void fakeMethod(int type) {
ClassFactory.getValue(type).generate();
}

Using final object in anonymous inner class results in null

I have a method that contains the following code:
public void myMethod(){
final MyDto expectedtDto = new MyDto();
MyRepository reposWithMock = new MyRepository(){
protected MyDao createDao(){
return new MyDao() {
public MyDto someMethod(){
return expectedtDto;
}
};
}
};
reposWithMock.doSomethingWithDao();
}
MyRepository.createDao() is called from the constructor of MyRepository.
MyDao.someMethod() is called from MyRepository.doSomethingWithDao().
However, the MyDao().someMethod() returns null instead of the expectedDto
Any idea why this is?
For clarification, some real working code:
package nl.tests;
public class TestAnon {
static class MyDao {
private int value;
public MyDao(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
static class Repository {
private MyDao dao;
public Repository() {
dao = createDao();
}
protected MyDao createDao(){
return new MyDao( 4 );
}
public MyDao getDao(){
return dao;
}
}
public static void main(String[] args) {
final MyDao testDao = new MyDao(8);
Repository repos = new Repository() {
protected MyDao createDao() {
if ( testDao == null ) {
System.out.println( "Error ");
return new MyDao(0);
}
return testDao;
}
};
System.out.println( "Dao :" + repos.getDao().getValue() );
}
}
This results in :
Error
Dao :0
Some additional information: I currently (have to) work with java 1.4.
My development environment is Rational Application Developer 7.
Addendum, to the given (and accepted answer). For the below code I've made the createDao() method public :
public static void main(final String[] args) {
final MyDao testDao = new MyDao(8);
Repository repos = new Repository() {
public MyDao createDao() {
if ( testDao == null ) {
System.out.println( "Error ");
return new MyDao(0);
}
return testDao;
}
};
System.out.println( "Dao :" + repos.getDao().getValue() );
System.out.println( "Dao :" + repos.createDao().getValue() );
}
Returns:
Error
Dao :0
Dao :8
It fails in Java 1.4 because the field containing the local variable is not yet initialized when the super constructor for Repository is executed.
It works in Java 1.5 and later, because then the field is initialized before the super constructor is called.
In general it is bad style to call methods which may be overridden in subclasses in a constructor, because it leads to this kind of problems.
According to what you provided a quick test outputs MyDto#190d11 or similar. So I bet you left out some important code which is responsible for some variable name hiding.
Test.java
public class Test {
public static void main(String args[]) {
new Test().myMethod();
}
public void myMethod() {
final MyDto expectedtDto = new MyDto();
MyRepository reposWithMock = new MyRepository() {
#Override
protected MyDao createDao() {
return new MyDao() {
#Override
public MyDto someMethod(){
return expectedtDto;
}
};
}
};
reposWithMock.doSomethingWithDao();
}
}
MyDto.java
public class MyDto {}
MyRepository.java
public abstract class MyRepository {
protected abstract MyDao createDao();
public void doSomethingWithDao() {
System.out.println(createDao().someMethod());
}
}
MyDao.java
public abstract class MyDao {
public abstract MyDto someMethod();
}
Make sure you actually override the method you think you do. Your IDE or #Override should help.
Is MyDto a child of MyDao?
Your return a MyDto when the method indicates you return a MyDao.
Maybe that is a piece of the problem.
A second solution could be:
Put the expectedtDto in the inner-class instead of the method.
Martijn
Your code works for me. The only way I could see that expectedDto could be null within the anonymous inner class is if you're referencing it on another thread without proper synchronization.
The test-case you described works fine for me.
You should provide minimal but complete standalone test-case that illustrates the problem to get help.

Categories

Resources