I am used to use generics in typed collections, but I never actually used them to develop something.
I have several classes like this:
public class LogInfoWsClient extends GenericWsClient {
public void sendLogInfo(List<LogInfo> logInfoList) {
WebResource ws = super.getWebResource("/services/logInfo");
try {
String response = ws.accept(MediaType.TEXT_HTML).type(MediaType.APPLICATION_XML).put(String.class, new GenericEntity<List<LogInfo>>(logInfoList) {
});
}
}
Where the only thing changing between one and another is the service String ("/services/info"), and the type of the list (LogInfo in this case)
I have refactored a couple of methods to a GenericWsClient class, but my objective would be to have something I can use like this:
List<LogInfo> myList = database.getList();
SuperGenericClient<List<LogInfo>> superClient = new SuperGenericClient<List<LogInfo>>();
superClient.send(myList,"/services/logInfo");
But I cannot figure out how to do it, or even if its possible. Would it be possible?
Yes it is possible infact if you look at java.util.collection package for example you will find all classes to be parameterzid.
So your class will be something like this
public SuperGenericClient<E> {
public E getSomething() {
return E;
}
}
Then to use it you will have
SuperGenericClient<String> myGenericClient = new SuperGenericClient<String>();
String something = myGenericClient.getSomething();
Extending your example itself your code will look like this:
public class SuperGenericClient<E> extends GenericWsClient {
public void send(List<E> entityList, String service) {
WebResource ws = super.getWebResource(service);
try {
String response = ws.accept(MediaType.TEXT_HTML).type(MediaType.APPLICATION_XML).put(String.class, new GenericEntity<E>(entityList) {
});
}
}
}
public class GenericEntity<E> {
public GenericEntity(List<E> list){
}
}
You must read this for a very good understanding of Generics.
You could write your class like the one below - you can apply the same idea to GenericEntity.
public class SuperGenericClient<T> extends GenericWsClient {
public void send(List<T> list, String service) {
WebResource ws = super.getWebResource(service);
try {
String response = ws.accept(MediaType.TEXT_HTML).type(MediaType.APPLICATION_XML).put(String.class, new GenericEntity<T>(list) {
});
}
}
}
You can then call it like that:
List<LogInfo> myList = database.getList();
SuperGenericClient<LogInfo> superClient = new SuperGenericClient<LogInfo>();
superClient.send(myList,"/services/logInfo");
Declare your class like this:
public class LogThing<T> {
public void sendLogInfo(List<T> list) {
// do thing!
}
}
And when you use it, do so like this:
List<LogInfo> myList = db.getList();
LogThing<LogInfo> superClient = new LogThing<LogInfo>();
superClient.sendLogInfo(myList);
Related
I'm making a game with libGDX that I want to export to HTML using Gradle. The issue comes when I use this method to get a list of actors. Apparently isInstance() and isInstanceOf are not compatible with GWT so I'm looking for a way to get around this. Gradle tell me isInstance is not defined. It runs fine on desktop.
public static ArrayList<BaseActor> getList(Stage stage, String className) {
ArrayList<BaseActor> list = new ArrayList<BaseActor>();
Class theClass = null;
try {
theClass = ClassReflection.forName("com.mygdx.game.actors." + className);
} catch (Exception error) {
error.printStackTrace();
}
for (Actor a : stage.getActors()) {
if (theClass.isInstance(a))
list.add((BaseActor) a);
}
return list;
}
The Actor class has a user object property (getUserObject()/setUserObject()) that you can use to attach data. You could make your BaseActor use this as a class tag property, and use an abstract method so you won't forget to add it to any of your Actor implementations.
abstract class BaseActor {
//...
public BaseActor() {
setUserObject(getClassTag());
//...
}
protected abstract String getClassTag();
}
class SomeSpecificActor extends BaseActor {
public SomeSpecificActor () {
super();
//...
}
#Override
protected String getClassTag() {
return "SomeSpecificActor";
}
}
public static ArrayList<BaseActor> getList(Stage stage, String classTag) {
ArrayList<BaseActor> list = new ArrayList<BaseActor>();
for (Actor a : stage.getActors()) {
if (classTag.equals(a.getUserObject()))
list.add((BaseActor) a);
}
return list;
}
I have an abstract class with a single abstract method; and a number of implementing classes (about 6).
The method returns an object that "needs" two parameters.
However, in some cases, only one of the two parameters is required.
Is there an elegant way to implement this case? (instead of return this parameter as empty)
public class NormResult {
protected List<String> normWords;
protected List<String> unNormWords;
public NormResult(List<String> normWords,List<String> unNormWords) {
this.normWords = normWords;
this.unNormWords = unNormWords;
}
public NormResult(List<String> normWords) {
this.normWords = normWords;
this.unNormWords = Collections.emptyList();
}
}
public abstract class AbstractNormalizer {
protected abstract List<NormResult> doNorm();
}
public class FirstNormImpl extends AbstractNormalizer {
protected List<NormResult> doNorm() {
List<String> normWords = new ArrayList<>(5);
List<String> unNormWords = new ArrayList<>(7);
NormResult result = new NormResult(normWords, unNormWords);
return result;
}
}
public class SecondNormImpl extends AbstractNormalizer {
protected List<NormResult> doNorm() {
List<String> normWords = new ArrayList<>(8);
NormResult result = new NormResult(normWords);
return result;
}
}
if you do this to members final:
protected final List<String> normWords;
protected final List<String> unNormWords;
then in the constructor you have to initialize them both... then you can set to an empty collection or a null reference the one you dont have/need
and your overloaded constructor can look like:
public NormResult(List<String> normWords, List<String> unNormWords) {
this.normWords = normWords;
this.unNormWords = unNormWords;
}
public NormResult(List<String> normWords) {
this(normWords, Collections.emptyList());
}
The two changes I would make:
Make the fields final
Use constructor telescoping
as in:
public NormResult(List<String> normWords) {
this(normWords(), Collections.emptyList());
}
to avoid even that simple "code duplication" of assigning values twice.
Beyond that; I agree with the comments; this approach looks reasonable.
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.
[EDIT: I've rewritten the code to further simplify it and focus on the issue at hand]
I'm working on this particular piece of code:
class SimpleFactory {
public SimpleFactory build() {return null}
}
class SimpleFactoryBuilder {
public Object build(final Class builderClazz) {
return new SimpleFactory() {
#Override
public SimpleFactory build() {
return new builderClazz.newInstance();
}
};
}
}
However, the builder in the return statement triggers the error "Cannot find symbol newInstance". It's as if builderClazz wasn't recognized as a class object.
How can I make it work?
EDIT: SOLUTION (thanks to dcharms!)
The code above is a partial simplification of the code I was dealing with. The code below is still simplified but includes all the components involved and includes the solution provided by dcharms.
package com.example.tests;
interface IProduct {};
interface ISimpleFactory {
public IProduct makeProduct();
}
class ProductImpl implements IProduct {
}
class SimpleFactoryBuilder {
public ISimpleFactory buildFactory(final Class productMakerClazz) {
return new ISimpleFactory() {
#Override
public IProduct makeProduct() {
try {
// the following line works: thanks dcharms!
return (IProduct) productMakerClazz.getConstructors()[0].newInstance();
// the following line -does not- work.
// return new productMakerClazz.newInstance();
}
catch (Exception e) {
// simplified error handling: getConstructors() and newInstance() can throw 5 types of exceptions!
return null;
}
}
};
}
}
public class Main {
public static void main(String[] args) {
SimpleFactoryBuilder sfb = new SimpleFactoryBuilder();
ISimpleFactory sf = sfb.buildFactory(ProductImpl.class);
IProduct product = sf.makeProduct();
}
}
You cannot instantiate a new object this way. builder is a Class object. Try instead the following:
return builder.getConstructors()[0].newInstance(anInput);
Note: this assumes you are using the first constructor. You may be able to use getConstructor() but I'm not sure how it would behave with the generic type.
First off - I'm rather novice at Java so if the question makes no sense do let me know.
Basically I'm making an Android app which communicates with my web service and so I've made a separate class to deal with the communication, which also includes the AsyncTask (I've removed a lot from the code here just for preview):
public class api {
private String caller = null;
Context that = null;
api(Context that) {
this.that = that;
this.caller = that.getClass().getSimpleName();
}
void call(String action) {
/* .... */
}
new back().execute(param1, param2);
}
void callback(String action, String result){
that.callback(action, result);
}
public class back extends AsyncTask<String, Void, String> {
public String response = null;
protected String doInBackground(String... params) {
response = connection.executeRequest(params[1]);
return response;
}
protected void onPostExecute(String result) {
callback("a", "b");
}
}
}
And when I use the class from some part of the app (let's say SomeClass.class), I do:
api WS = new api(this);
WS.call("....");
And it's supposed to execute the function 'callback' which is in SomeClass.
But the key problem here is this line:
that.callback(action, result);
Eclipse makes me add the name of the "caller" class in the cast:
(SomeClass) that.callback(action, result);
But that doesn't work for me, because I use the 'api' class from many different classes, so ideally I need to put a variable in the cast. I do get the name of the "caller" class here:
this.caller = that.getClass().getSimpleName();
//obviously this won't work:
(this.caller) that.callback(action, result);
Is there anyway to do that, or am I doing something fundamentally wrong?
Thank you.
Currently your api class accepts a Context object in its default constructor. It would make more sense to extend Context with a new class which contains a callback method which you can then override in subclasses such as SomeClass, that would negate the need for casting in your api class. e.g:
public class APIContext extends Context
{
public void callback( String action, String result )
{
/* ... */
}
}
public class SomeClass extends APIContext
{
#Override
public void callback( String action, String result )
{
/* ... */
}
}
public class api
{
private APIContext callerContext = null;
public api( APIContext context )
{
this.callerContext = context;
}
public void callback( String action, String result )
{
callerContext.callback( action, result );
}
}