I have been struggling for some time trying to define a generic interface, but I fail to
achieve what I want. The following is a simplified example of the problem.
Let's say I have a generic Message class
public class Message<T> {
private T content;
public void setContent(T content) {
this.content = content;
}
public T getContent() {
return content;
}
}
and then I want to define an interface for transfering things:
public interface Transfer<Message<T>> {
public void send(Message message);
}
The problem is that the compiler does not accept this, and always complains about
the second '<' character, no matter what variations I try.
How do I specify this interface so that it is bound to a generic type (based on Message)
and also have access to the parameterized type?
My plan was to use this interface like the following:
public class Carrier<Message<T>> implements Transfer<Message<T>> {
public void send(Message message) {
T content = message.getContent();
print(content);
}
public static void print(String s) {
System.out.println("The string equals '" + s + "'");
}
public static void print(Integer i) {
System.out.println("The integer equals " + i);
}
public static void main(String[] args) {
Carrier<Message<String>> stringCarrier = new Carrier<Message<String>>();
Message<String> stringMessage = new Message<String>("test");
stringCarrier.send(stringMessage);
Carrier<Message<Integer>> integerCarrier = new Carrier<Message<Integer>>();
Message<Integer> integerMessage = new Message<Integer>(123);
integerCarrier.send(integerMessage);
}
}
I have done some searching and reading (among other things Angelika's generics faq), but I am not able to tell if this is not possible or if I am doing it wrong.
Update 2009-01-16: Removed the original usage of "Thing" instead of "Message< T >" (which was used because with that I was able to compile without getting syntax errors on the interface).
It looks to me like you want:
public class Carrier<Thing extends Message<Foo>, Foo>
implements Transfer<Thing>
That way the compiler will know that thing is a Message<Foo> and will therefore have a getContent() method.
You'll need to use it as:
Carrier<Message<String>, String>
But you've currently got a bit of a disconnect. You're implementing Transfer<Thing> but you're trying to use thing as if it's a Message<Thing> look at your send method - you're calling it with a String and an Integer. Those classes don't have getContent() methods.
I suspect you should actually be implementing Transfer<Message<Thing>> instead of Transfer<Thing>
Regardless of how you solve your generics problem, your code will not compile because you do not have a print method that takes a type of T as a parameter.
I believe you will have to do instance of checks if you want the functionality you are looking for. So, I don't think you gain any value from the generic type in this case.
You only need to specify T for the class, and then use Message< T > for your argument/return types.
public interface Transfer<T> {
public void send(Message<T> message);
}
The reason you don't use Message< T > is because you're providing the 'this is a message' context in your arguments and return types.
Related
I know this question has been asked a million times but I'm not quite sure I have the solution I need. There could very well be a "NO" answer to this question but I am open to other solutions to this problem.
I am implementing my own Exception class which extends from another which also implements Iterable.
class TCBPackageException extends TCBRuntimeException implements Iterable<TCBRuntimeException> {
private List<TCBRuntimeException> exceptions = new LinkedList<>();
TCBPackageException(Throwable t) {
super(t);
}
class TCBPackageIterator extends Iterator<TCBRuntimeException> {
public boolean hasNext() {
...
}
public TCBRuntimeException next() {
...
}
}
public void addException(TCBRuntimeException e) {
exceptions.add(e);
}
// Here's My ISSUE
// When getMessage() is Called on TCBPackageException I want the accumulation of all the messages stored.
#Override
public String getMessage() {
StringBuffer buffer = new StringBuffer(super.getMessage());
for (TCBException ex : exceptions) {
buffer.append(ex.getMessage());
}
return buffer.toString();
}
// If I use an Iterator and end up getting this as the FIRST object, I just want the message of THIS exception.
public String getMessage() {
return super.getMessage();
}
From https://docs.oracle.com/javase/tutorial/java/javaOO/methods.html
The Java programming language supports overloading methods, and Java can distinguish between methods with different method signatures. This means that methods within a class can have the same name if they have different parameter lists (there are some qualifications to this that will be discussed in the lesson titled "Interfaces and Inheritance").
Concidering this, you can't define two methods having absolute the same signature (annotations like #Override do not belong to signature). If you would define two methods getMessage() witout any difference, the compiler would not know which one you are trying to call by o.getMessage().
You have to name them differently or define different set of parameters. Proposal:
#Override
public String getNestedMessages() {
StringBuffer buffer = new StringBuffer(super.getMessage());
for (TCBException ex : exceptions) {
buffer.append(ex.getMessage());
}
return buffer.toString();
}
The second method getMessage() is absolutely obsolete then, since you would automatically call it from the super class if you do not override it.
Ok, while I tried to find a title that explains the problem I probably have to expand on it.
Recently I implemented a small program that will be used to control a tape library. Knowing it had to work with multiple different types of tape library so the following design was developed.
interface Tapelibrary<T extends TapeDrive> {
List<T> getListofDrives();
void doSomethingWithDrive(T d);
}
class SpecificTapeLibrary implements Tapelibrary<HPDrive> {
private List<HPDrive> driveList;
SpecificTapeLibrary() {
driveList.add(new HPDrive());
driveList.add(new HPDrive());
driveList.add(new HPDrive());
}
#Override
public List<HPDrive> getListofDrives() {
return driveList;
}
#Override
public void doSomethingWithDrive(HPDrive d) {
d.doSomethingHPspecific();
}
}
abstract class TapeDrive {
void doSomething() {
}
}
class HPDrive extends TapeDrive {
void doSomethingHPspecific() {
}
}
The correct tape library is determined by a factory based on command line arguments.
public static void main(String[] args) {
Tapelibrary<? extends TapeDrive> t = new TapeLibraryFabric().get();
List<? extends TapeDrive> listOfDrives = t.getListofDrives();
// the user selects a drive by using a small UI or something
TapeDrive selectedDrive = listOfDrives.get(0);
t.doSomethingWithDrive(selectedDrive); // compiler error
}
This does make sense since the compiler would have to explicitly cast the supertype TapeDrive to the subtype HPDrive which is expected by the doSomethingWithDrive(HPDrive) methods in SpecificTapeLibrary
How would this be solved in a good oop way? I ended up not using generics and casting inside the doSomethingWithDrive method (as suggested here:How to Pass a Child Class into a method requiring Super Class as parameter). But that can't be the optimal solution.
While writing this post another solution popped into my head which is much cleaner. The DriveSelector class encapsulates the selection process.
class DriveSelector {
<T> T selectDrive(List<T> inputList) {
// give the user an UI or something to select a drive
return inputList.get(0);
}
}
// the tape library then uses the selector
public void doSomethingWithSelectedDrive(DriveSelector selector) {
HPDrive t = selector.selectDrive(driveList);
t.doSomethingHPspecific();
}
Any other ideas?
Do all of your work in a generic method:
static <T extends TapeDrive> void doStuff(Tapelibrary<T> t) {
List<T> listOfDrives = t.getListofDrives();
// the user selects a drive by using a small UI or something
T selectedDrive = listOfDrives.get(0);
t.doSomethingWithDrive(selectedDrive);
}
Then call this from your main method:
Tapelibrary<? extends TapeDrive> t = new TapeLibraryFabric().get();
doStuff(t);
Ideone demo
The way this works is that it removes all of the wildcards - the thing about wildcards is that the compiler treats every one as different, even if the values are derived from a single generic instance. By putting things into the generic method like this, you allow the compiler to know that all of the Ts are the same type - thus it can know that the calls are safe.
I'm trying to create a builder pattern that uses generics to provide type checking on some of the methods. Currently I have the following working:
ParameterBuilder.start(String.class).setName("foo").setDefaultValue("Hello").build();
ParameterBuilder.start(Integer.class).setName(bar).setDefaultValue(42).build();
ParameterBuilder.start(Boolean.class).setName(bar).setDefaultValue(false).build();
Using the code:
public class ParameterBuilder<T> {
private String name;
private T defaultValue;
public static <T2> ParameterBuilder<T2> start(Class<T2> type) {
return new ParameterBuilder<T2>();
}
// Other methods excluded for example
}
So the type of the input for the setDefaultValue method is defined by what's passed into the start method, just as I want.
But now I want to extend what's being passed into start() to contain a little more information. Essentially I want to pass in a "type" for the parameters I creating. Sometimes these parameters will be things like "email", "url" etc. The default value will still be of a known type (String in those cases), so I'd like to have something like:
ParameterBuilder.start(EMAIL).setName("email").setDefaultValue("foo#bar.com").build();
ParameterBuilder.start(URL).setName("website").setDefaultValue("http://www.somewhere.com").build();
Where at the moment EMAIL & URL are enums, containing amongst other things - the class of the default value. But if I go down this route, how would I instantiate the parameter builder?
public static <T2> ParameterBuilder<T2> start(ParameterType paramType) {
Class<T2> type = paramType.getTypeClass();
// How do I instantiate my ParameterBuilder with the right type?
}
If it can't be done using enums (which I can see being the case), does anyone have a suggestion for a different solution?
I think you need one enum per class type (I don't see how you could have one enum cover several types and keep the thing working). In that case, a common generic interface could do what you want. You can then create some sort of factory to provide the enum constants if that helps.
This compiles:
static interface ParameterType<T> {}
static enum ParameterTypeEnum implements ParameterType<String> { EMAIL; }
public static void main(String[] args) {
ParameterBuilder
.start(ParameterTypeEnum.EMAIL)
.setName("email")
.setDefaultValue("foo#bar.com")
.build();
}
public static class ParameterBuilder<T> {
private String name;
private T defaultValue;
public static <T2> ParameterBuilder<T2> start(ParameterType<T2> paramType) {
return new ParameterBuilder<T2>();
}
ParameterBuilder<T> setName(String name) {
this.name = name;
return this;
}
ParameterBuilder<T> setDefaultValue(T defaultValue) {
this.defaultValue = defaultValue;
return this;
}
void build() {}
}
I'm not sure the context in what you want to use this, but I think the following might be an option.
You can follow the Open/Closed principle and create an interface Parameter and have one implementation per type. The benefit of this, is that you don't need to add a new enum value for each new Parameter you want. You can later pass the class to ParameterBuilder rather than the enum and the ParameterBuilder and Parameter would work together to build what you need.
So ParameterBuilder.start() could return an instance of the specific Parameter and the parameter might have different methods depending on the type of parameter.
I don't think this answer is really good, but hopefully can give you a hint in how to build a potential solution for your context.
You could create an object hierachie for these Email and Url types
public class DefaultType {
protected String name;
protected String defaultValue;
//some constructor
}
public class EmailType extends DefaultType {
...
}
public class URLType extends DefaultType {
...
}
then the parameter builder could look something like this:
public static ParameterBuilder start(DefaultType type) {
ParameterBuilder builder = new ParameterBuilder(type);
builder.setType(type);
return builder;
}
Then you could call it like this:
ParameterBuilder.start(new EmailType("name","value");...
does this help or dont you want to go in this direction?
When you use the Visitor pattern and you need to get a variable inside visitor method, how to you proceed ?
I see two approaches. The first one uses anonymous class :
// need a wrapper to get the result (which is just a String)
final StringBuild result = new StringBuilder();
final String concat = "Hello ";
myObject.accept(new MyVisitor() {
#Override
public void visit(ClassA o)
{
// this concatenation is expected here because I've simplified the example
// normally, the concat var is a complex object (like hashtable)
// used to create the result variable
// (I know that concatenation using StringBuilder is ugly, but this is an example !)
result.append(concat + "A");
}
#Override
public void visit(ClassB o)
{
result.append(concat + "B");
}
});
System.out.println(result.toString());
Pros & Cons :
Pros : you do not need to create a class file for this little behavior
Cons : I don't like the "final" keyword in this case : the anonymous class is less readable because it calls external variables and you need to use a wrapper to get the requested value (because with the keyword final, you can't reassign the variable)
Another way to do it is to do an external visitor class :
public class MyVisitor
{
private String result;
private String concat;
public MyVisitor(String concat)
{
this.concat = concat;
}
#Override
public void visit(ClassA o)
{
result = concat + "A";
}
#Override
public void visit(ClassB o)
{
result = concat + "B";
}
public String getResult()
{
return result;
}
}
MyVisitor visitor = new MyVisitor("Hello ");
myObject.accept(visitor);
System.out.println(visitor.getResult());
Pros & Cons :
Pros : all variables are defined in a clean scope, you don't need a wrapper to encapsulate the requested variable
Cons : need an external file, the getResult() method must be call after the accept method, this is quite ugly because you need to know the function call order to correctly use the visitor
You, what's your approach in this case ? Preferred method ? another idea ?
Well, both approaches are valid and imo, it really depends on whether you would like to reuse the code or not. By the way, your last 'Con' point is not totally valid since you do not need an 'external file' to declare a class. It might very well be an inner class...
That said, the way I use Visitors is like this:
public interface IVisitor<T extends Object> {
public T visit(ClassA element) throws VisitorException;
public T visit(ClassB element) throws VisitorException;
}
public interface IVisitable {
public <T extends Object> T accept(final IVisitor<T> visitor) throws VisitorException;
}
public class MyVisitor implements IVisitor<String> {
private String concat;
public MyVisitor(String concat) {
this.concat = concat;
}
public String visit(ClassA classA) throws VisitorException {
return this.concat + "A";
}
public String visit(ClassB classB) throws VisitorException {
return this.concat + "B";
}
}
public class ClassA implements IVisitable {
public <T> T accept(final IVisitor<T> visitor) throws VisitorException {
return visitor.visit(this);
}
}
public class ClassB implements IVisitable {
public <T> T accept(final IVisitor<T> visitor) throws VisitorException {
return visitor.visit(this);
}
}
// no return value needed?
public class MyOtherVisitor implements IVisitor<Void> {
public Void visit(ClassA classA) throws VisitorException {
return null;
}
public Void visit(ClassB classB) throws VisitorException {
return null;
}
}
That way, the visited objects are ignorant of what the visitor wants to do with them, yet they do return whatever the visitor wants to return. Your visitor can even 'fail' by throwing an exception.
I wrote the first version of this a few years ago and so far, it has worked for me in every case.
Disclaimer: I just hacked this together, quality (or even compilation) not guaranteed. But you get the idea... :)
I do not see an interface being implemented in your second example, but I believe it is there. I would add to your interface (or make a sub interface) that has a getResult() method on it.
That would help both example 1 and 2. You would not need a wrapper in 1, because you can define the getResult() method to return the result you want. In example 2, because getResult() is a part of your interface, there is no function that you 'need to know'.
My preference would be to create a new class, unless each variation of the class is only going to be used once. In which case I would inline it anonymously.
From the perspective of a cleaner design, the second approach is preferrable for the same exact reasons you've already stated.
In a normal TDD cycle I would start off with an anonymous class and refactored it out a bit later. However, if the visitor would only be needed in that one place and its complexity would match that of what you've provided in the example (i.e. not complex), I would have left it hanging and refactor to a separate class later if needed (e.g. another use case appeared, complexity of the visitor/surrounding class increased).
I would recommend using the second approach. Having the visitor in its full fledged class also serves the purpose of documentation and clean code. I do not agree with the cons that you have mentioned with the approach. Say you have an arraylist, and you don't add any element to it and do a get, surely you will get a null but that doesn't mean that it is necessarily wrong.
One of the points of the visitor pattern is to allow for multiple visitor types. If you create an anonymous class, you are kind of breaking the pattern.
You should change your accept method to be
public void accept(Visitor visitor) {
visitor.visit(this);
}
Since you pass this into the visitor, this being the object that is visited, the visitor can access the object's property according to the standard access rules.
I've an existing method which looks like this:
public void parseMessage(String message){
...
...
...
}
and the method is called by calling it as shown below
String message;
parseMessage(message);
I need to modify it for it to process a new type of message. The parser for the new type of message which is called from the parseMessage method expects some properties first before it can parse the message. What i am thinking of doing is passing the message as an object that looks like this
public class MessageObject{
private String message;
private String namespace;
private String xmlVersion;
}
I can then call the existing method as
Object messageObject;
parseMessage(messageObject);
I can then use it on the other side by casting it as (MessageObject)messageObject.
Is this the correct way of doing it or is there a better approach. Are there any dangers to doing the above?
ps. i have to use the above casting approach as im using JDK1.4
Thanks
Update
I cant modify the parseMessage method. It has a call inside it which calls the parse() method for each relevant parser.
public void parseMessage(String message){
...
...
parser.parse(message)
}
The parser reference shown above is an object that implements an interface "Parser". The new parser i am introducing follows this structure and it also implements the "Parser" interface. The only modifications (i.e. the casting to MessageObject) are in the new parser.
i cant change the existing parseMethod as that will require changing all of the existing parsers that implement the "Parser" interface. I want to avoid having to call a specific parser depending on message type.
If i use the approach i am suggesting, existing parsers will still recieve a String message while the new parser will recieve a String but it will need to cast it back to MessageObject first.
Edit
I have had to test this based on Sergey's comments.
The Interface
package com;
public interface Parser{
public void parse(String message);
}
package com;
MessageA Parser
public class MessageAParser implements Parser{
public void parse(String message){
System.out.println("Parsing A");
}
}
MessageB Parser
package com;
public class MessageAParser implements Parser{
public void parse(String message){
System.out.println("Parsing A");
}
}
MessageC parser (This expects an object)
package com;
public class MessageCParser implements Parser{
public void parse(Object message){
MessageObject mobject = (MessageObject)message;
System.out.println("Parsing C" + mobject.getMessage());
}
public void parse(String m){}
}
The parser manager that calls the relevant parser.
package com;
import java.util.HashMap;
public class ParserManager{
public ParserManager() {
prepare();
}
HashMap parsers = new HashMap();
public void prepare(){
parsers.put("A",new MessageAParser());
parsers.put("B",new MessageBParser());
parsers.put("C",new MessageCParser());
}
public void parseMessage(String msgType, String message){
((Parser)parsers.get(msgType)).parse(message);
}
}
package com;
The controller.
public class ControlClass{
public static void main(String[] args){
ParserManager pManager = new ParserManager();
//Parse A
pManager.parseMessage("A","ATEXT TO PARSE");
//Parse B
pManager.parseMessage("B","BTEXT TO PARSE");
//Parse C
Object mobject = new MessageObject();
pManager.parseMessage("C",(String)mobject);
}
}
When i run the above Controller class it outputs the text for the first two messages but fails for the third one.
Parsing A
Parsing B
java.lang.ClassCastException
at com.ControlClass.main(ControlClass.java:17)
Exception in thread "main"
The MessageObject class is not a String subclass, so you can't pass it instead of String. And you can't subclass String since it's declared as final. So there is no way you can pass a MessageObject (whatever that is) to the existing parseMessage() function.
i cant change the existing parseMethod
as that will require changing all of
the existing parsers that implement
the "Parser" interface. I want to
avoid having to call a specific parser
depending on message type.
What exactly is the signature of the Parser.parse()? If it's parse(String message), then you can't possibly pass there anything else than a String.
However, if that's the only reason you don't want to modify the existing parseMessage(), then there is a workaround:
public void parseMessage(Object message) { // changed to Object
...
...
if (message instanceof String)
parser.parse((String) message);
else {
if (message instanceof MessageObject) {
if (!(parser instanceof MessageObjectParser)) {
throw new IllegalArgumentException(
"A MessageObject is passed, but not supported by the parser");
}
((MessageObjectParser) parser).parse((MessageObject) message);
} else {
throw new IllegalArgumentException(
"Messages of type " + parser.getClass() + " aren't supported");
}
}
}
It's a bit ugly, but will probably work. Now you only have your new parsers implement the new MessageObjectParser interface, which should extend the old Parser.
You can overload parseMessage so it comes in two flavors: one that takes a String argument and one that takes a MessageObject argument.
I think there a couple of cleaner solutions here. The first is that you could extend the class that implements parseMessage and add an additional method.
public void parseMessage(MessageObject messageObject) {
// Additional stuff here
...
// Call through to original
parseMessage(messageObject.message);
}
Alternatively, you could just decorate the class that contains parseMessage. However, I am assuming that you can modify the class that contains parseMessage since you say you want to cast it in there anyway.
If you have more and more types of things to parse, instead of overloading the parse method, you should introduce an interface :
public interface Parseable {
public String getMessage();
}
The MessageObject would implement Parseable, and you could use an anonymous adapter class for String objects :
final String m = "theMessageToParse";
parseMessage(new Parseable() {
public String getMessage() {
return m;
}
});