AspectJ compiler bug leads to StackOverflowError - java

I run into a StackOverflow error of the AspectJ compiler today and I thought I should share it on StackOverflow :-)
To reproduce the error I made a toy example
public abstract class Node<T,Q extends Node<T,Q>> implements WithParent<Q>{
private T content;
//getter and setter for content
}
public aspect WithParentAspect {
private T WithParent<T>.parent;
public T WithParent<T>.getParent() {
return this.parent;
}
public void WithParent<T>.setParent(T parent) {
this.parent=parent;
}
}
public interface WithParent<T> { }
public class StringContentNode extends Node<String, StringContentNode>{
public static void main (String [] args) {
StringContentNode root = new StringContentNode();
StringContentNode leaf = new StringContentNode();
root.setContent("root");
leaf.setContent("leaf");
leaf.setParent(root);
System.out.println(leaf);
System.out.println(leaf.getParent());
}
}
Trying to compile this code results in the following error:
java.lang.StackOverflowError
at org.aspectj.weaver.World$TypeMap.put(World.java:1198)
at org.aspectj.weaver.World.resolve(World.java:398)
at org.aspectj.weaver.World.resolve(World.java:277)
at org.aspectj.weaver.World.resolve(World.java:229)
at org.aspectj.weaver.UnresolvedType.resolve(UnresolvedType.java:615)
at org.aspectj.weaver.ReferenceType.isAssignableFrom(ReferenceType.java:621)
at org.aspectj.weaver.ReferenceType.isAssignableFrom(Ref ...
bleFrom(ReferenceType.java:459)
at org.aspectj.weaver.TypeVariable.isASubtypeOf(TypeVariable.java:201)
However, if I modify the Generics in the Node class to
public abstract class Node<T,Q extends Node<T,?>> implements WithParent<Q>{
...
(notice the ? instead of Q), the program works, and prints what you would expect:
Node (content=leaf, parent=Node (content=root, parent=null))
Node (content=root, parent=null)
even though Eclipse complains that
The method setParent(StringContentNode) is undefined for the type StringContentNode
if I leave the WithParent Interface empty as is now, or that
The type StringContentNode must implement the inherited abstract method
WithParent.getParent()
If I define the getter and the setter in the interface.
Should I signal the bug? Is there a cleaner way to achieve the same functionality, without incurring in any weird compilation issue?
Thanks!

It seems no one will propose a workaround that allows to keep implementing recursive generics interfaces through AspectJ in spite of the bug.
It would have been interesting to find such a solution but I guess it is not likely to exist.
Please cast your votes on the bug report https://bugs.eclipse.org/bugs/show_bug.cgi?id=526707 if you can.
Cheers.
update: according to Tim Wright the bug is fixed in version 1.9.5 of aspectjrt

Related

Java Hibernate: What would be the better design to get rid of casting

I use Hibernate for persistence.
Suppose I have an entity which contains information about the document and the necessary information for producing it (either printing or sending by email). Just like this:
The problem here is that DocumentInformation holds reference to abstract class DocumentProductionConfiguration not to the subclasses DocumentPrintConfiguration or DocumentEmailConfiguration.
So when I actually need to get appropriate configuration I have two choices: either use instanceof + casting or use visitor pattern to trick Java so that it would actually understand in the runtime which configuration it is dealing with.
Using casting:
public class XmlBuilder{
public XMLMessage buildXmlMessage(DocumentInformation documentInformation){
if(documentInformation.getDocumentProductionConfiguration() instanceOf DocumentPrintConfiguration){
DocumentPrintConfiguration printConfig = (DocumentPrintConfiguration) documentInformation.getDocumentProductionConfiguration();
XMLMessageConfig xmlConfig = handlePrintConfig(printConfig);
}
}
public XMLMessageConfig handlePrintConfig(DocumentPrintConfiguration printConfig){
....build that XMLMessageConfig....
}
}
Using visitor pattern:
I need to add a new interface for XmlBuilder to implement
public interface XmlBuilderVisitor<T> {
T handlePrintConfig(DocumentPrintConfiguration printConfig);
}
public class XmlBuilder implements XmlBuilderVisitor<XMLMessageConfig> {
#Override
public XMLMessageConfig handlePrintConfig(DocumentPrintConfiguration printConfig){
....build that XMLMessageConfig....
}
public XMLMessage buildXmlMessage(DocumentInformation documentInformation){
XMLMessageConfig xmlMessageConfig = documentInformation.getDocumentProductionConfiguration().buildConfiguration(this);
}
}
public abstract class DocumentProductionConfiguration{
public abstract <T> T buildConfiguration(XmlBuilderVisitor<T> visitor);
}
public class DocumentPrintConfiguration extends DocumentProductionConfiguration{
public <T> T buildConfiguration(XmlBuilderVisitor<T> visitor){
return visitor.handlePrintConfig(this);
}
}
Both of these solutions are kinda meh... The first one because it violates open-closed principle (I will need to always maintain these ifs...).
The second one in this sense is better: once you add new configuration, compiler will guide you through the process: first, you will need to implement appropriate method in the configuration itself, then in all the visitor classes. On the other hand, it is pretty awkward that I am basically passing service to the entity...
So I feel like I am treating symptoms rather than the problem. Maybe the design itself needs some changes? But I am not sure how it could be improved...
I would reccomend pushing the "handle" functionality into the DocumentProductionConfiguration and subclasses. So that the DocumentPrintConfiguration would contain a handle function that builds and returns a XMLMessageConfig. Then your XmlBuilder becomes:
public class XmlBuilder{
public XMLMessage buildXmlMessage(DocumentInformation documentInformation){
XMLMessageConfig xmlConfig = documentInformation.getDocumentProductionConfiguration().handle();
}
}

Can the cast of Java Generics with #SuppressWarnings("unchecked") cause runtime exceptions

I have 2 interfaces Sub and Obs as illustrated below:
public interface Sub<O extends Obs<? extends Sub>>{
public void addObs(O o);
public void removeObs(O o);
public void notifyObs();
}
public interface Obs<S entends Sub<?>>{
public void update(S s);
}
Now there are 2 concrete implementations of the above as class Vie which implements Obs and class Mod which implements Sub as below:
public class Mod implements Sub<Vie<Mod>>{
private Vie<Mod>[] vies = new Vie<Mod>[0];//Here is the error.
public void addObs(Vie<Mod> vie){
vies = addToArray(vies, vie);
//Some other code;
}
public void removeObs(Vie<Mod> vie){
vies = removeFromArray(vies, vie);
//Some other code;
}
public void notifyObs(){
for(Vie<Mod> v : this.vies){
v.update(this);
}
}
}
public class Vie<M extends Mod> implements Obs<M>{
private M mod;
public void update(M){
//some code;
}
public void setMod(M mod){
this.mod.removeObs(this); //Here is the error.
mod.addObs(this); //Here is the error.
this.mod = mod;
}
}
In the above code of Mod there is an error of initialisation of the array vies. The correction that is applicable is :
#SuppressWarnings("unchecked")
private Vie<Mod>[] vies = (Vie<Mod>[])new Vie<Mod>[0];
And for the Vie class's setMod method the correction that can be applied is:
#SuppressWarnings("unchecked")
public void setMod(M mod){
this.mod.removeObs((Vie<Mod>)this);
mod.addObs((Vie<Mod>)this);
this.mod = mod;
}
As we can see that both the above cases we had to explicitly type cast the instances before they could be used by the program also we had to add #SuppressWarnings("unchecked") so that the compiler does not throw any compile error.
Now my understanding of #SuppressWarnings("unchecked") is that I am explicitly asking the compiler not to check the type of the instance of the variable at the compile time. If this is correct then can I run into any runtime ClassCastException?
Also can this above code be modified such that I do not require any #SuppressWarnings("unchecked")?
Additional Info
I have updated the code to show the utilisation of the variable vies. This above is a basic implementation of Observer Pattern. Kindly note that this is the complete implementation as far as the Observer Pattern is concerned. What I mean to say is in actual implementation the real classes inherits other classes and interfaces whose methods are not mentioned here. But as far as vies and mod variable is concerned, this is complete.
The issue with creation of an array of a parameterized type has to do with the array not being able to check that elements added are the right type as arrays usually do. Since you only use the array inside the class and don't expose it to the outside, it's fine and you can just suppress the warning. The type you use and the suppression of the warning are internal implementation details of the class and outside code doesn't care.
The type mismatch of passing this to removes() and addObs is a bigger issue. Vie<M> and Vie<Mod> are incompatible types. It's not clear why you have Vie be generic. If you didn't make it generic, it would work:
public class Mod implements Sub<Vie> {
private Vie[] vies = new Vie[0];
public void addObs(Vie vie) {
//vies = addToArray(vies, vie);
//Some other code;
}
public void removeObs(Vie vie) {
//vies = removeFromArray(vies, vie);
//Some other code;
}
public void notifyObs() {
for (Vie v : this.vies) {
v.update(this);
}
}
}
public class Vie implements Obs<Mod> {
private Mod mod;
public void update(Mod mod) {
//some code;
}
public void setMod(Mod mod) {
this.mod.removeObs(this);
mod.addObs(this);
this.mod = mod;
}
}
If you want to be able to have this code work for Mod and Vie subclasses, then it would be more complicated.
The compiler warning you are suppressing is designed to warn about possible errors due to type erasure. Type erasure means at run-time your parameterized classes are not parameterized, but plain types. This means that the runtime knows Vie is Vie but it can't check what object type it holds in mod (until you fetch it).
The general class of problems are explained here: Java GenericsFAQ. Your example is similar to the Wrapper example given.
Here is an example of the dangers of ignoring unchecked warnings using conventional classes:
ArrayList<String> as = new ArrayList<String>();
ArrayList<Integer> ai = new ArrayList<Integer>();
ArrayList ao1;
ArrayList ao2;
as.add("Hello");
ao1 = as;
ao2 = ai;
ao2.add(ao1.get(0));
Integer i = ai.get(0); // Class cast exception, even though no casting done
Your code is vaguely similar and I think it helps to understand the above example to see what you are doing. You won't see any errors in the code you have supplied as you are putting Vie<M extends Mod> objects to a Vie<Mod> holder. The problem lies when you come get to things out of your Vie<Mod> holder and you assume they could be Vie<ParticularM> objects, which is not necessarily true.
You don't have any methods at the moment fetching the Vie objects, but if you did, at runtime the compiler would not be able to tell the exact type of the the object that Vie was wrapping, so any casts that you make to Vie<M> are really advice to the compiler and cannot actually be enforced.
In your code, it is all held together by the Vie class itself which moderates access to the Mod class and ensures (I think) that you are always putting consistent objects in the array.
But your code is not complete and you are only a step away from adding some piece of code that allows a Vie<M2 extends Mod> object to be put in an array where you think are Vie<M1 extends Mod> objects.
So, in summary, I think the current code is safe as it stands in isolation, but any changes could introduce errors that the compiler could not detect.

OOP: How to write families of classes to work together?

Yesterday I asked this question, and the solution posted by #JB Nizet worked perfectly. However, that answer, as well as a few other answers/comments got me thinking in a different direction altogether.
Essentially, I have the following classes:
Load
HttpLoad extends Load
Target
HttpTarget extends Target
Controller
The Controller's job is to Target::fire() a Load, and doesn't care which Target is firing which Load:
// Inside Controller.java
Target target = getTarget();
Load load = getLoad();
target.fire(load);
However, I might some day write a FtpLoad extends Load, and I don't want to be able to fire a FtpLoad at an HttpTarget. So the essence of the above-referenced question was how do I do this, to which, the answer was generics.
However, as the answerer pointed out, this solution is a violation of the Liksov Substitution Principle. Other answerer/commenters seemed to indicate that what I was doing wasn't necessarily good OOP practices.
So now I'm asking: how do I expose an API so that the Controller can be Load- and Target-agnostic, but still enforce that the proper Load subclass is fired on the proper Target type, all without violating Liskov Substitution?
And, if this is impossible to do (without violating Liskov), then what is the normal approach to a problem like this? Thanks in advance!
If HttpTarget.fire allows any Load as parameter, it is its job to check if it can fire this Load. So either the Controller calls fire blindly, and fire checks if the given target can fire that kind of Load (with instanceof), or you include a function canFire in every target that implements this check and is called by the Controller.
The typing problem here is that HttpTarget is not a Liskov subtype of Target, because semantically it is attempting to strengthen the preconditions of Target#fire(Load) to require the Load be HttpLoad.
This can be trivially repaired by declaring Target#fire(Load) throws IncompatibleLoadException and having a default implementation that always throws, forcing Controller to deal with the fact that a mismatched Load can be passed in.
The easy way is to do some checking in your code to make sure the classes match up. You can use the instanceof keyword to check if it's the correct class.
Best is to implement abstract class or an interface and use instanceof as mentioned before.
With an abstract class:
public abstract class TargetLoad {
public abstract void fire(TargetLoad i);
}
public class Load extends TargetLoad {
#Override
public void fire(TargetLoad i) {
if (i instanceof Target) return;
// do fire stuff
}
}
public class Target extends TargetLoad {
#Override
public void fire(TargetLoad i) {
if (i instanceof Load) return;
// do fire stuff
}
}
with an interface:
public interface TargetLoad {
public void fire(TargetLoad i);
}
public class Load implements TargetLoad {
#Override
public void fire(TargetLoad i) {
if (i instanceof Target) return;
// do fire stuff
}
}
public class Target implements TargetLoad {
#Override
public void fire(TargetLoad i) {
if (i instanceof Load) return;
// do fire stuff
}
}
In your Controller you refer to your objects as TargetLoad
TargetLoad target = getTarget();
TargetLoad load = getLoad();
target.fire(load);
load.fire(target);
load.fire(load); //this will do nothing
target.fire(target); //this will do nothing
I strongly disagree with the slew of answers recommending to use instanceof. Well-written OOP code very rarely needs to use instanceof, and using instanceof will generally make your code awkward and difficult to maintain. As a general rule, avoid instanceof if at all possible.
The previous question you referred to provided a solution using generics. I'm not sure you left the generics code out of your question here; go back to your generic code. Now, add the following method to your driver.
private <L extends Load> void runSuite(TestSuite<L> suite) {
Target<L> target = testSuite.getTarget();
L load = testSuite.getLoad();
target.fire(load);
}

Simulate static abstract and dynamic linking on static method call in Java

Introduction
As a disclaimer, I'v read Why can't static methods be abstract in Java and, even if I respectfully disagree with the accepted answer about a "logical contradiction", I don't want any answer about the usefulness of static abstract just an answer to my question ;)
I have a class hierarchy representing some tables from a database. Each class inherits the Entity class which contains a lot of utility methods for accessing the database, creating queries, escaping characters, etc.
Each instance of a class is a row from the database.
The problem
Now, in order to factorize as much code as possible, I want to add information about related columns and table name for each class. These informations must be accessible without a class instance and will be used in Entity to build queries among other things.
The obvious way to store these data are static fields returned by static methods in each class. Problem is you can't force the class to implement these static methods and you can't do dynamic linking on static methods call in Java.
My Solutions
Use a HashMap, or any similar data structure, to hold the informations. Problem : if informations are missing error will be at runtime not compile time.
Use a parallel class hierarchy for the utility function where each corresponding class can be instantiated and dynamic linking used. Problem : code heavy, runtime error if the class don't exist
The question
How will you cope with the absence of abstract static and dynamic linking on abstract method ?
In a perfect world, the given solution should generate a compile error if the informations for a class are missing and data should be easily accessible from withing the Entity class.
The answer doesn't need to be in Java, C# is also ok and any insight on how to do this without some specific code in any language will be welcomed.
Just to be clear, I don't have any requirement at all besides simplicity. Nothing have to be static. I only want to retrieve table and columns name from Entity to build a query.
Some code
class Entity {
public static function afunction(Class clazz) { // this parameter is an option
// here I need to have access to table name of any children of Entity
}
}
class A extends Entity {
static String table = "a";
}
class B extends Entity {
static String table = "b";
}
You should use the Java annotation coupled with the javac annotation processor, as it's the most efficient solution. It's however a bit more complicated than the usual annotation paradigm.
This link shows you how you can implement an annotation processor that will be used at the compile time.
If I reuse your example, I'd go this way:
#Target(ElementType.TYPE)
#Retention(RetentionType.SOURCE)
#interface MetaData {
String table();
}
abstract class Entity {}
#MetaData(table="a")
class A extends Entity {}
#MetaData(table="b")
class B extends Entity {}
class EntityGetter {
public <E extends Entity> E getEntity(Class<E> type) {
MetaData metaData = type.getAnnotation(MetaData.class);
if (metaData == null) {
throw new Error("Should have been compiled with the preprocessor.");
// Yes, do throw an Error. It's a compile-time error, not a simple exceptional condition.
}
String table = metaData.table();
// do whatever you need.
}
}
In your annotation processing, you then should check whether the annotation is set, whether the values are correct, and make the compilation fail.
The complete documentation is available in the documentation for the package javax.annotation.processing.
Also, a few tutorials are available on the Internet if you search for "java annotation processing".
I will not go deeper in the subject as I never used the technology myself before.
I have run into the same problems as you, and am using the following approach now. Store Metadata about columns as annotations and parse them at runtime. Store this information in a map. If you really want compile time errors to appear, most IDEs (Eclipse e.g.) support custom builder types, that can validate the classes during build time.
You could also use the compile time annotation processing tool which comes with java, which can also be integrated into the IDE builds. Read into it and give it a try.
In Java the most similar approach to "static classes" are the static enums.
The enum elements are handed as static constants, so they can be accesed from any static context.
The enum can define one or more private constructors, accepting some intialization parameters (as it could be a table name, a set of columns, etc).
The enum class can define abstract methods, which must be implemented by the concrete elements, in order to compile.
public enum EntityMetadata {
TABLE_A("TableA", new String[]{"ID", "DESC"}) {
#Override
public void doSomethingWeirdAndExclusive() {
Logger.getLogger(getTableName()).info("I'm positively TableA Metadata");
}
},
TABLE_B("TableB", new String[]{"ID", "AMOUNT", "CURRENCY"}) {
#Override
public void doSomethingWeirdAndExclusive() {
Logger.getLogger(getTableName()).info("FOO BAR message, or whatever");
}
};
private String tableName;
private String[] columnNames;
private EntityMetadata(String aTableName, String[] someColumnNames) {
tableName=aTableName;
columnNames=someColumnNames;
}
public String getTableName() {
return tableName;
}
public String[] getColumnNames() {
return columnNames;
}
public abstract void doSomethingWeirdAndExclusive();
}
Then to access a concrete entity metadata this would be enough:
EntityMetadata.TABLE_B.doSomethingWeirdAndExclusive();
You could also reference them from an Entity implemetation, forcing each to refer an EntityMetadata element:
abstract class Entity {
public abstract EntityMetadata getMetadata();
}
class A extends Entity {
public EntityMetadata getMetadata() {
return EntityMetadata.TABLE_A;
}
}
class B extends Entity {
public EntityMetadata getMetadata() {
return EntityMetadata.TABLE_B;
}
}
IMO, this approach will be fast and light-weight.
The dark side of it is that if your enum type needs to be really complex, with lot of different params, or a few different complex overriden methods, the source code for the enum can become a little messy.
Mi idea, is to skip the tables stuff, and relate to the "There are not abstract static methods". Use "pseudo-abstract-static" methods.
First define an exception that will ocurr when an abstract static method is executed:
public class StaticAbstractCallException extends Exception {
StaticAbstractCallException (String strMessage){
super(strMessage);
}
public String toString(){
return "StaticAbstractCallException";
}
} // class
An "abstract" method means it will be overriden in subclasses, so you may want to define a base class, with static methods that are suppouse to be "abstract".
abstract class MyDynamicDevice {
public static void start() {
throw new StaticAbstractCallException("MyDynamicDevice.start()");
}
public static void doSomething() {
throw new StaticAbstractCallException("MyDynamicDevice.doSomething()");
}
public static void finish() {
throw new StaticAbstractCallException("MyDynamicDevice.finish()");
}
// other "abstract" static methods
} // class
...
And finally, define the subclasses that override the "pseudo-abstract" methods.
class myPrinterBrandDevice extends MyDynamicDevice {
public static void start() {
// override MyStaticLibrary.start()
}
/*
// ops, we forgot to override this method !!!
public static void doSomething() {
// ...
}
*/
public static void finish() {
// override MyStaticLibrary.finish()
}
// other abstract static methods
} // class
When the static myStringLibrary doSomething is called, an exception will be generated.
I do know of a solution providing all you want, but it's a huge hack I wouldn't want in my own code nowadays:
If Entity may be abstract, simply add your methods providing the meta data to that base class and declare them abstract.
Otherwise create an interface, with methods providing all your data like this
public interface EntityMetaData{
public String getTableName();
...
}
All subclasses of Entity would have to implement this interface though.
Now your problem is to call these methods from your static utility method, since you don't have an instance there. So you need to create an instance. Using Class.newInstance() is not feasable, since you'd need a nullary constructor, and there might be expensive initialization or initialization with side-effects happening in the constructor, you don't want to trigger.
The hack I propose is to use Objenesis to instantiate your Class. This library allows instatiating any class, without calling the constructor. There's no need for a nullary constructor either. They do this with some huge hacks internally, which are adapted for all major JVMs.
So your code would look like this:
public static function afunction(Class clazz) {
Objenesis objenesis = new ObjenesisStd();
ObjectInstantiator instantiator = objenesis.getInstantiatorOf(clazz);
Entity entity = (Entity)instantiator.newInstance();
// use it
String tableName = entity.getTableName();
...
}
Obviously you should cache your instances using a Map<Class,Entity>, which reduces the runtime cost to practically nothing (a single lookup in your caching map).
I am using Objenesis in one project of my own, where it enabled me to create a beautiful, fluent API. That was such a big win for me, that I put up with this hack. So I can tell you, that it really works. I used my library in many environments with many different JVM versions.
But this is not good design! I advise against using such a hack, even if it works for now, it might stop in the next JVM. And then you'll have to pray for an update of Objenesis...
If I were you, I'd rethink my design leading to the whole requirement. Or give up compile time checking and use annotations.
Your requirement to have static method doesn't leave much space for clean solution. One of the possible ways is to mix static and dynamic, and lose some CPU for a price of saving on RAM:
class Entity {
private static final ConcurrentMap<Class, EntityMetadata> metadataMap = new ...;
Entity(EntityMetadata entityMetadata) {
metadataMap.putIfAbsent(getClass(), entityMetadata);
}
public static EntityMetadata getMetadata(Class clazz) {
return metadataMap.get(clazz);
}
}
The way I would like more would be to waste a reference but have it dynamic:
class Entity {
protected final EntityMetadata entityMetadata;
public Entity(EntityMetadata entityMetadata) {
this.entityMetadata=entityMetadata;
}
}
class A extends Entity {
static {
MetadataFactory.setMetadataFor(A.class, ...);
}
public A() {
super(MetadataFactory.getMetadataFor(A.class));
}
}
class MetadataFactory {
public static EntityMetadata getMetadataFor(Class clazz) {
return ...;
}
public static void setMetadataFor(Class clazz, EntityMetadata metadata) {
...;
}
}
You could get even get rid of EntityMetadata in Entity completely and leave it factory only. Yes, it would not force to provide it for each class in compile-time, but you can easily enforce that in the runtime. Compile-time errors are great but they aren't holy cows after all as you'd always get an error immediately if a class hasn't provided a relevant metadata part.
I would have abstracted away all meta data for the entities (table names, column names) to a service not known by the entities them selfs. Would be much cleaner than having that information inside the entities
MetaData md = metadataProvider.GetMetaData<T>();
String tableName = md.getTableName();
First, let me tell you I agree with you I would like to have a way to enforce static method to be present in classes.
As a solution you can "extend" compile time by using a custom ANT task that checks for the presence of such methods, and get error in compilation time. Of course it won't help you inside you IDE, but you can use a customizable static code analyzer like PMD and create a custom rule to check for the same thing.
And there you java compile (well, almost compile) and edit time error checking.
The dynamic linking emulation...well, this is harder. I'm not sure I understand what you mean. Can you write an example of what you expect to happen?

Java Generics Question

Alright, I thought I understood generics pretty well, but for some reason I can't get my head wrapped around why this doesn't work. I have two classes, or I should say that Google has two classes (I'm trying to implement their Contacts API). They have a ContactEntry class (abbreviated below):
package com.google.gdata.data.contacts;
public class ContactEntry extends BasePersonEntry<ContactEntry> {
public ContactEntry() {
super();
getCategories().add(CATEGORY);
}
public ContactEntry(BaseEntry<?> sourceEntry) {
super(sourceEntry);
}
}
I left off one or two methods, but nothing important, its really just an implementation of its parent class BasePersonEntry which has most of the important stuff that concerns a person entry abbreviated code below:
package com.google.gdata.data.contacts;
public abstract class BasePersonEntry<E extends BasePersonEntry> extends
BaseEntry<E> {
public BasePersonEntry() {
super();
}
public BasePersonEntry(BaseEntry<?> sourceEntry) {
super(sourceEntry);
}
public List<CalendarLink> getCalendarLinks() {
return getRepeatingExtension(CalendarLink.class);
}
public void addCalendarLink(CalendarLink calendarLink) {
getCalendarLinks().add(calendarLink);
}
public boolean hasCalendarLinks() {
return hasRepeatingExtension(CalendarLink.class);
}
}
Now... what I can't quite understand is if I do something like the following:
public void method1(StringBuilder sb, ContactEntry contact) {
if (contact.hasCalendarLinks()) {
for (CalendarLink calendarLink : contact.getCalendarLinks()) {
...
}
}
}
Everything works fine. It is able to interpret that getCalendarLinks returns a list of type CalendarLink. However, if I want to abstract this method and have my method use BasePersonEntry, like the following:
public void method1(StringBuilder sb, BasePersonEntry entry) {
if (entry.hasCalendarLinks()) {
for (CalendarLink calendarLink : entry.getCalendarLinks()) {
...
}
}
}
I get a compiler error:
incompatible types
found : java.lang.Object
required: com.google.gdata.data.contacts.CalendarLink
For the life of me I just can't understand why? The call to getCalendarLinks is the EXACT same method (via inheritance), its returning the EXACT same thing. Maybe it has to do with BasePersonEntry being an abstract class?
If anyone, can shed some light on this I would be very much obliged. If it helps you can find a full version of this source code hosted by Google here: Link To Google Library Download. I was attempting this with version 1.41.3 of their gdata-java libraries.
The problem with your new definition, is that it's using Raw type not Generic type.
As a result type is erased from everything, including getCalendarLinks and its signature is reduced to equivalent of List<Object> getCalendarLinks( )
To fix it, change declaration to:
public void method1(StringBuilder sb, BasePersonEntry<?> entry)
Note <?> after BasePersonEntry. This way it's generic type.
Also, you probably want to change the class generic declaration to
public abstract class BasePersonEntry<E extends BasePersonEntry<E> >
Without <E> your compiler ( or IDE ) will generate an unchecked warning.

Categories

Resources