New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AutoValue: Support for extending a class. #277
Comments
See also #269 |
Yes, this is a known restriction. The code example above should work but does not. |
@jbgi I usually agree with composition over inheritance but in this case all three classes are on the same package and I don't want to define an interface but rather make sure that it is clear where ArgsA and ArgsB differ for each specialized usage, by class A and B. It is cumbersome to have to always do something like ArgsA.getCommonArgs().getTheActualArgIWant() instead of being able to do ArgsA.getTheActualArgIWant(). Thanks @eamonnmcmanus, I think the use of a |
@dballesteros7 not always, just once: class ArgsA {
...
abstract CommonArgs getCommonArgs();
TheActualArgIWant getTheActualArgIWant{
return getCommonArgs().getTheActualArgIWant();
}
...
} |
But then I would be re-writing a method for every arg from |
yes. for free. as well as headaches as soon as your domain model diverges from being a nice hierarchy. |
What I mean is that inheritance may be fine in some isolated cases like yours but I'd rather not see support for it in auto-value, which would promote this "bad" practice. |
Is inheritance for value types really such a bad idea if the super class is abstract? As far as I remember Effective Java (I don't have it at hand), this is fine and problems only arise if there exist instance of both the super class and sub classes (because then for example equals() cannot be implemented sanely). |
Having an ancestor shared between different |
@PhilippWendler @eamonnmcmanus @dballesteros7 Algebraic Data Types are a more flexible solution than inheritance for this kind of problem. Have a look at https://github.com/derive4j/derive4j to implement them in Java easily. |
@jbgi very nice! |
@eamonnmcmanus I think the constructors are not generated correctly when an ancestor class is used in 1.1, or at least the behaviour is unintuitive. In the docs it states that the generated constructor should match the order that the abstract accessors are declared in, but if i have public abstract class BaseArgs {
public abstract Object getFoo();
public abstract Object getBar();
} and @AutoValue
public abstract class SameArgs extends BaseArgs {
}
...
@AutoValue
public abstract class MoreArgs extends BaseArgs {
public abstract Object getMoreFoo();
} The generated constructor I get is AutoValue_MoreArgs(
Object bar,
Object foo,
Object moreFoo) {
if (bar == null) {
throw new NullPointerException("Null bar");
}
this.bar = bar;
if (foo == null) {
throw new NullPointerException("Null foo");
}
this.foo = foo;
if (moreFoo == null) {
throw new NullPointerException("Null moreFoo");
}
this.moreFoo = moreFoo;
} which doesn't match what I would expect. Shouldn't it be I think I've seen it randomly change the order of the arguments too (ie there were no changes to I'm not sure whether having a child that adds no additional accessors ( |
I tried using those exact classes and I see the constructor with parameters in the order I would expect: foo, bar, moreFoo. Are you using Eclipse by any chance? We've had problems with parameter ordering there because it didn't follow the annotation processing spec. Those should be fixed as of Eclipse 4.5, though. |
Intellij...with the eclipse compiler actually, i think, so that would make sense. |
IntelliJ uses javac by default but can be configured to use ECJ (the Eclipse compiler). |
True, I use javac for 'real' builds but for IDE dev work ECJ is quite convenient. |
Feel free to log a separate bug about the behaviour you are seeing. If you have a way of knowing which ECJ version IntelliJ is using that would be very helpful. With versions prior to the one shipped with Eclipse 4.5, there was a bug where methods were sorted into alphabetical order within each class, instead of the source-code order. That looks like what you are seeing; you could try some experiments to confirm. AutoValue has code to try to undo the sorting, but it's possible that in the IntelliJ/ECJ situation it doesn't work for some reason. |
OK I raised #292. |
@eamonnmcmanus any update on this? Is it planned to be implemented or not? |
It's still on my list, and has moved nearer to the top after finishing a number of other tasks that had been languishing (coming soon to a PR near you). I don't know when I'll get to it, though. FTR fixing it is not completely straightforward because of a longstanding bug in the Eclipse compiler. I was able to work around that bug in another context, though, so it should be doable. |
@eamonnmcmanus sorry but I wasn't clear, I was asking about allowing a builder to extend another class. Do you know anything about this? |
A fix is in the works that should allow the example at the top of this issue to compile. Meanwhile, it is always possible to override the inherited methods in the final Builder subclass with their explicit types. So in the original example you could declare Were you asking about something else? |
This is what I was asking, I know you can override, but in my case I have common base class for like 20-30 other classes and it has around 10 fields and this will add a big overhead, also it will create a big overhead for maintaining. Thank you for the answer. If it is possible, do you know an estimation when the fix would be finished? |
I'd expect it to be in 1.3-SNAPSHOT within the next week. |
As hinted by @eamonnmcmanus, this issue was indeed fixed in the Thanks for the hard work ! |
This issue became a little confused, with different topics being discussed, but I think we can indeed consider it closed. |
Suppose I have a set of base arguments that I need to share with two classes, and I define the following base class.
Now I want to add baz for class A and qux for class B.
And similarly for ArgsB. However this fails with: Setter methods must return ArgsA.Builder, despite the generic annotation.
Is this something sane to do? Could it be fixed in the way the types are being compared to support the generic annotation? I could have optional parameters in BaseArgs but I would like to keep separate definitions of these arguments, and reuse any validations in the base class.
For now my only solution is to rewrite the builder setters in each of the two "concrete" classes.
The text was updated successfully, but these errors were encountered: