Given the following abstract class:
public abstract class BaseVersionResponse<T extends BaseVO> {
public abstract void populate(T versionVO);
}
and the following child class:
public class VersionResponseV1 extends BaseVersionResponse<VersionVOV1>
{
protected String testFieldOne;
protected String testFieldTwo;
public String getTestFieldOne() {
return testFieldOne;
}
public void setTestFieldOne(String value) {
this.testFieldOne = value;
}
public String getTestFieldTwo() {
return testFieldTwo;
}
public void setTestFieldTwo(String value) {
this.testFieldTwo = value;
}
#Override
public void populate(VersionVOV1 versionVO) {
this.setTestFieldOne(versionVO.getFieldOne());
this.setTestFieldTwo(versionVO.getFieldTwo());
}
I desire to do something like this from a calling method:
public void getVersionInfo(String version) {
BaseVO versionVO = null;
BaseVersionResponse<? extends BaseVO> baseVersionResponse = null;
baseVersionResponse = createVersionResponse(version);
versionVO = createVersionVO(version);
baseVersionResponse.populate(versionVO);
}
where createVersionResponse(...) and createVersionVO(...) look like this:
public BaseVersionResponse<? extends BaseVO> createVersionResponse(String version) {
BaseVersionResponse<? extends BaseVO> specificVersionResponse = null;
if (version.equalsIgnoreCase("V1")) {
specificVersionResponse = new VersionResponseV1();
} else if (version.equalsIgnoreCase("V2"))
specificVersionResponse = new VersionResponseV2();
return specificVersionResponse;
}
public BaseVO createVersionVO(String version) {
BaseVO versionVO = null;
if (version.equalsIgnoreCase("V1")) {
versionVO = new VersionVOV1();
} else if (version.equalsIgnoreCase("V2"))
versionVO = new VersionVOV2();
return versionVO;
}
and VersionVOV1 looks like this:
public class VersionVOV1 extends BaseVO {
private String fieldOne = null;
private String fieldTwo = null;
private String fieldThree = null;
public String getFieldOne() {
return fieldOne;
}
public void setFieldOne(String fieldOne) {
this.fieldOne = fieldOne;
}
public String getFieldTwo() {
return fieldTwo;
}
public void setFieldTwo(String fieldTwo) {
this.fieldTwo = fieldTwo;
}
public String getFieldThree() {
return fieldThree;
}
public void setFieldThree(String fieldThree) {
this.fieldThree = fieldThree;
}
}
My problem arises when I try to compile this line of code:
baseVersionResponse.populate(versionVO);
in getVersionInfo(...). I'm getting a message that looks like this:
The method populate(capture#3-of ?) in the type BaseVersionResponse is not applicable for the arguments (BaseVO)
on the populate method above.
My thought was (which is apparently incorrect) that since the baseVersionResponse is, at this point in the code, actually a specific child instance, that the class would know exactly which populate method to call from that specific child class.
What am I doing wrong here? Is there a better way to do this if this isn't the correct approach?
Thank you for your time!
Ok, I took a better look at this today. The problem is that the wildcard, while the right way to go, precludes you from doing:
BaseVO versionVO = createVersionVO(version);
Because the populate call wants an extension of BaseVO, not an actual BaseVO, which doesn't qualify. That means you can't pass that versionVO variable directly.
So, to keep the type checking in place, which I think is good because you'll always want an implementation, leave pretty much everything as-is above, and change your BaseVersionResponse class to something like:
public abstract class BaseVersionResponse<T extends BaseVO> {
public T getVersion(BaseVO versionVO) {
try {
return (T) versionVO;
} catch (ClassCastException e) {
throw new IllegalArgumentException();
}
}
public abstract void populate(BaseVO versionVO);
}
So, populate method now takes a BaseVO, and there's a new getVersion method to do some explicit casting for us. This should be ok since we know that the factory will always supply the right thing, but if another caller doesn't, an IllegalArgumentException is thrown.
Now, in your response class implementation, change the populate method accordingly:
public void populate(BaseVO version) {
VersionVOV1 versionVO = getVersion(version);
this.setTestFieldOne(versionVO.getFieldOne());
this.setTestFieldTwo(versionVO.getFieldTwo());
}
So, we've changed the populate method to take BaseVO, and the getVersion method does the casting for us. All the other type checks still apply, and we're good to go.
The casting makes it feel not as clean, but for the factory approach you're using, it's really the only way (I can think of) to keep the guarantees made by the type declarations and the code pattern in tact.
Hope that helps!
If you just take out the capture of type (the "<?>"), and leave it unchecked, it should work just fine. Even using type Object would have compiled.
But, given your specific example, what you probably want is the method:
public BaseVersionResponse<?> createVersionResponse(String version)
Changed to:
public BaseVersionResponse<? extends BaseVO> createVersionResponse(String version)
Then, instead of using
BaseVersionResponse<?>
use
BaseVersionResponse<? extends BaseVO>
Since you know that the return type will be one of those things that implements the interface/class.
Related
In my program, the user needs to input what type of players the game will have. The players are "human", "good" (for a good AI), "bad" (for a bad AI) and "random" (for a random AI). Each of these players have their own class that extend one abstract class called PlayerType.
My struggle is mapping a String to the object so I can A) create a new object using the String as sort of a key and B) get the related String from an object of its subclass
Ultimately, I just want the implicit String to only appear once in the code so I can change it later if needed without refactoring.
I've tried using just a plain HashMap, but that seems clunky with searching the keys via the values. Also, I'm guessing that I'll have to use the getInstance() method of Class, which is a little less clunky, which is okay if it's the only way.
What I would do is create an enum which essentially functions as a factory for the given type.
public enum PlayerTypes {
GOOD {
#Override
protected PlayerType newPlayer() {
return new GoodPlayer();
}
},
BAD {
#Override
protected PlayerType newPlayer() {
return new BadPlayer();
}
},
RANDOM {
#Override
protected PlayerType newPlayer() {
return new RandomPlayer();
}
};
protected abstract PlayerType newPlayer();
public static PlayerType create(String input) {
for(PlayerTypes player : PlayerTypes.values()) {
if(player.name().equalsIgnoreCase(input)) {
return player.newPlayer();
}
}
throw new IllegalArgumentException("Invalid player type [" + input + "]");
}
)
Because then you can just call it like so:
String input = getInput();
PlayerTypes.create(input);
Of course, you'll get an IllegalArgumentException which you should probably handle by trying to get the input again.
EDIT: Apparently in this particular case, you can replace that loop with just merely
return PlayerTypes.valueOf(input).newPlayer();
And it'll do the same thing. I tend to match for additional constructor parameters in the enum, so I didn't think of using valueOf(), but it's definitely cleaner.
EDIT2: Only way to get that information back is to define an abstract method in your PlayerType class that returns the PlayerTypes enum for that given type.
public class PlayerType {
public abstract PlayerTypes getType();
}
public class GoodPlayer extends PlayerType {
#Override
public PlayerTypes getType() {
return PlayerTypes.GOOD;
}
}
I like the answer provided by Epic but I don't find maps to be clunky. So it's possible to keep a map and get the constructor call directly.
Map<String, Supplier<PlayerType> map = new HashMap<>();
map.put("human", Human::new);
Human h = map.get("human").get();
The two main options I can think of:
Using Class.newInstance(), as you mentioned (not sure if you had this exact way in mind):
// Set up your map
Map<String, Class> classes = new HashMap<String, Class>();
classes.put("int", Integer.class);
classes.put("string", String.class);
// Get your data
Object s = classes.get("string").newInstance();
You could use Class.getDeclaredConstructor.newInstance if you want to use a constructor with arguments (example).
Another option is using switch:
Object getObject(String identifier) {
switch (identifier) {
case "string": return new String();
case "int": return new Integer(4);
}
return null; // or throw an exception or return a default object
}
One potential solution:
public class ForFunFactory {
private ForFunFactory() {
}
public static AThing getTheAppropriateThing(final String thingIdentifier) {
switch (thingIdentifier) {
case ThingImplApple.id:
return new ThingImplApple();
case ThingImplBanana.id:
return new ThingImplBanana();
default:
throw new RuntimeException("AThing with identifier "
+ thingIdentifier + " not found.");
}
}
}
public interface AThing {
void doStuff();
}
class ThingImplApple implements AThing {
static final String id = "Apple";
#Override
public void doStuff() {
System.out.println("I'm an Apple.");
}
}
class ThingImplBanana implements AThing {
static final String id = "Banana";
#Override
public void doStuff() {
System.out.println("I'm a Banana.");
}
}
Given these classes:
public class VersionVOV1 extends BaseVO {
private String fieldOne = null;
public String getFieldOne() {
return fieldOne;
}
public void setFieldOne(String fieldOne) {
this.fieldOne = fieldOne;
}
public class VersionVOV2 extends BaseVO {
private String fieldFour = null;
public String getFieldFour() {
return fieldFour;
}
public void setFieldFour(String fieldFour) {
this.fieldFour = fieldFour;
}
}
public class BaseVO {
// common code here
}
I have a calling method doSomething which returns a specific child class based upon an input string:
public BaseVO doSomething(String version) {
BaseVO versionVO = doSomethingVersioned(createVersionVO(version));
return versionVO;
}
The remaining methods are:
private BaseVO createVersionVO(String version) {
BaseVO versionVO = null;
if (version.equalsIgnoreCase("V1")) {
versionVO = new VersionVOV1();
} else if (version.equalsIgnoreCase("V2"))
versionVO = new VersionVOV2();
return versionVO;
}
protected VersionVOV1 doSomethingVersioned(VersionVOV1 versionVO) throws Exception {
versionVO.setFieldOne("The versionVO is of type: " + versionVO.getClass());
versionVO.setFieldTwo("Field two");
versionVO.setFieldThree("Field three");
return versionVO;
}
protected VersionVOV2 doSomethingVersioned(VersionVOV2 versionVO) throws Exception {
versionVO.setFieldOne("The versionVO is of type: " + versionVO.getClass());
versionVO.setFieldThree("Field three");
versionVO.setFieldFour("Field four");
return versionVO;
}
As you can see I've overridden doSomethingVersioned to take in a specific child class. My problem however lies with the compilation error that looks like this on doSomethingVersioned: The method doSomethingVersioned(VersionVOV1) in the type VersionExample is not applicable for the arguments (BaseVO).
I've tried returning a type of <T extends BaseVO> from createVersionVO but then I get other compilation errors in that method stating Type mismatch: cannot convert from VersionVOV1 to T.
I feel like this should be easier than I'm making it. How can I keep this overall pattern but allow this to compile?
Thanks to everyone who helps!
What you want is the pattern Factory Method. Note: there really is no benefit from genericity here. You are merely creating something then the presumption is it will go on its way. Generics tend to yield the greatest benefit when you are wanting to leverage code that is orthogonal to the domain objects, e.g. collections.
I am getting a compilation error. I want my static method here to return a factory that creates and return Event<T> object. How can I fix this?
import com.lmax.disruptor.EventFactory;
public final class Event<T> {
private T event;
public T getEvent() {
return event;
}
public void setEvent(final T event) {
this.event = event;
}
public final static EventFactory<Event<T>> EVENT_FACTORY = new EventFactory<Event<T>>() {
public Event<T> newInstance() {
return new Event<T>();
}
};
}
Generic parameters of a class do not apply to static members.
The obvious solution is to use a method rather than a variable.
public static <U> EventFactory<Event<U>> factory() {
return new EventFactory<Event<U>>() {
public Event<U> newInstance() {
return new Event<U>();
}
};
}
The syntax is more concise in the current version of Java.
It is possible to use a the same instance of EventFactory stored in a static field, but that requires an unsafe cast.
You have:
public final class Event<T> {
...
public final static EventFactory<Event<T>> EVENT_FACTORY = ...
}
You cannot do this. T is a type that is associated with a specific instance of an Event<T>, and you cannot use it in a static context.
It's hard to give you good alternate options without knowing more about what exactly you are trying to do, as this is sort of an odd-looking factory implementation. I suppose you could do something like (put it in a method instead):
public final class Event<T> {
...
public static <U> EventFactory<Event<U>> createEventFactory () {
return new EventFactory<Event<U>>() {
public Event<U> newInstance() {
return new Event<U>();
}
};
};
}
And invoke it like:
EventFactory<Event<Integer>> factory = Event.<Integer>createEventFactory();
Or, if you don't want to be explicit (you don't really need to be, here):
EventFactory<Event<Integer>> factory = Event.createEventFactory();
Why don't you get rid of the whole static member of Event thing and either keep the factories separate, e.g.:
public final class GenericEventFactory<T> extends EventFactory<Event<T>> {
#Override public Event<T> newInstance() {
return new Event<T>();
}
}
And use, e.g., new GenericEventFactory<Integer>() where appropriate?
I have a class that i'm uses a generic Type that extends the interface zwave
everything is fine until i try to access a zwave variable for some reason the rm.keyword gives a "NullPointerException". if I cast it to the class scene it works, but that is not what I want
public <T extends zwave> T Find(List<T> Zwave,List<List<String>> listofinputstrings)
{
for(List<String> lst: listofinputstrings)
{
for(String str: lst)
{
for (T rm: Zwave)
{
//*** problem is here
//rm.keyword is always gives a NullPointerException unless i cast it to a class
if (rm.keyword.equals( str.toLowerCase()))
{
return rm;
}
}
}
}
return null;
}
//here is the interface
interface zwave
{
public String keyword="";
public String zwaveID="";
}
//here is a class that implements the interface
public class Scene implements zwave
{
String name;
String keyword;
String zwaveID;
public Scene(String Name,String Keyword,String ZwaveID)
{
name= Name;
zwaveID= ZwaveID;
keyword = Keyword;
}
}
edit
Working code
//search class
public <T extends searchable> T Find(List<T> searchableclasses, List<List<String>> listofinputstrings)
{
for(List<String> lst: listofinputstrings)
{
for(String str: lst)
{
for (T searchable: searchableclasses)
{
for(String key: searchable.GetKeywords())
{
if ( key.equals(str.toLowerCase()))
{
return searchable;
}
}
}
}
}
return null;
}
//abstract class
abstract class searchable
{
String[] keywords; //using array so i can use java's param ability
public List<String> GetKeywords()
{
return new ArrayList(Arrays.asList(keywords));
}
}
//actual class
public class Scene extends searchable
{
String name;
String zwaveID;
public Scene(String Name,String ZwaveID,String... Keywords)
{
name= Name;
zwaveID= ZwaveID;
keywords = Keywords;
}
}
If you don't wanna cast you can do some thing like this:
public <T extends zwave> T Find(List<T> Zwave,List<List<String>> listofinputstrings)
{
for(List<String> lst: listofinputstrings)
{
for(String str: lst)
{
for (T rm: Zwave)
{
if(rm instanceof Scene){
Method method=null;
try {
method = rm.getClass().getMethod("getKeyword");
if ( method.invoke(rm).equals( str.toLowerCase()))
{
return rm;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
return null;
}
NOte:define getKeyword method in Scene class:
I can customize it more with the help of java.lang.reflect. You would not even need to use instance of Scene. But I think you can do it yourself. And hope it will help.
use Reflection API to call at run time.
You need to be using a getter method. When you say rm.keyword, that's referring to a constant (zwave.keyword), which is the empty string. When you cast to Scene, the compiler sees that it's a field and looks it up instead.
Generally, you should make fields like name and keyword private unless you have a specific reason not to and use getter and setter methods to manipulate them.
The variables defined in the interface are final static public even though you didn't explicitly define. When the variable is final, once the value is assigned you cannot reassign it again.
Since you have defined as empty string ("") it will take that value. But you define the variable again in Scene class. So when you cast to Scene object will refer this variable and not the variable in the interface. Otherwise it refers to interface variable.
I have error when I send this:
myClaass.put(new ImenResult(1).Show());
myClaass.put(new ImenResult(2));
I understand why I have got this problem because I send to class which have interface parameter. My question is: what I have to add to interface to send this data and haven`t got error because this structure have to be this same (not my decision) because later I can send String or another things (Class). I know this is very difficult question.
Program:
Class_1 myClaass = new Class_1();
myClaass.put(new ImenResult(1).Show());
myClaass.put(new ImenResult(2));
myClaass.put(new ImenResult(3));
ImenResult:
public class ImenResult implements IImenResult{
public Integer i;
public ImenResult(Integer i ) {
this.i = i;
}
#Override
public Integer Show() {
return i;
}
Class_1
public class Class_1 implements IQRack{
public List<IAdant> adan;
public void put(IAdant value) {
adan.add(value);
}
}
IAdan
public interface IAdant {
}
Thanks for help I told you this is difficult question (of course for people who are not Java specialist) but topic is fixed. I gave you points. Thanks again for helped. [closed]
you should implement the method put(Integer) in Class_1 for this to work
public class Class_1 implements IQRack {
public List<IAdant> adan;
public void put(IAdant value) {
adan.add(value);
}
void put(Integer Show) {
throw new UnsupportedOperationException("Not yet implemented");
}
}
UPDATE
After your comment i think this is what you are trying to do:
public class Class_1 implements IQRack {
private List<IAdant> adan = new ArrayList<IAdant>();
public Class_1(IAdant i) {
this.put(i);
}
void put(IAdant Show) {
throw new UnsupportedOperationException("Not yet implemented");
}
}
public class IAdant {
Boolean bValue;
String sValue;
Integer iValue;
public IAdant(Object o) {
if (o.getClass().isInstance(new Integer(1))) {
iValue = (Integer) o;
} else if (o.getClass().isInstance(false)) {
bValue = (Boolean) o;
} else if (o.getClass().isInstance("")) {
sValue = (String) o;
}
}
}
The line: myClaass.put(new ImenResult(1).Show()); will fail, because myClaass.put() is expecting to get an object that implements IAdant, but you are sending and Integer. Integer does not implement IAdant.
myClaass.put(new ImenResult(1).Show());
myClaass.put(new ImenResult(2));
first case would file, cuz, your put method expects IAdant(any that that implements IAdant) and you are passing an integer as the show method would return one.
second case would fail because of the same reason that your ImenResult class is not implementing or a Type of IAdant.
if you want the second case to work, implement IAdant in ImenResult class.
public class ImenResult implements IImenResult,IAdant{
//implement the methods from both the interfaces
}
now myClaass.put(new ImenResult(2)); line would work with out any compiler errors.
If you wanna get the first case myClaass.put(new ImenResult(1).Show()); to compile , you have to overload the put method in myClass class.
public void put(int val) {
//do your logic here
}