英文:
JPA Abstract Inheritance with List<AbstractClass>
问题
我的代码:
@MappedSuperclass
public abstract class Header {
public abstract List<Line> getLines();
}
@Entity
public class ChildHeader extends Header{
@OneToMany
public List<ChildLine> getLines();
}
@MappedSuperclass
public abstract class Line {
public abstract Header getHeader();
}
@Entity
public class ChildLine extends Line {
@ManyToOne
public ChildHeader getHeader();
}
问题:我得到错误消息:“错误:在'ChildHeader'中的'getLines()'与'Header'中的'getLines()'冲突;尝试使用不兼容的返回类型”。
尝试的解决方法:将List<Line>
更改为<T extends Line> List<T>
,将List<ChildLine>
更改为<T extends ChildLine> List<T>
新错误:在'ChildHeader'中的'getLines()'与'Header'中的'getLines()'冲突;两种方法具有相同的擦除,但都没有覆盖另一个方法。
尝试的解决方法:尝试使用Line[]
和ChildLine[]
代替列表
新错误:"List/array必须使用@OrderColumn
(或@IndexColumn
)"进行注释,但没有排序列。数组的顺序无关紧要,但似乎@OneToMany
或JPA需要一个排序列。
这是一个无法解决的情况。我该怎么办?
英文:
My code:
@MappedSuperclass
public abstract class Header {
public abstract List<Line> getLines();
}
@Entity
public class ChildHeader extends Header{
@OneToMany
public List<ChildLine> getLines();
}
@MappedSuperclass
public abstract class Line {
public abstract Header getHeader();
}
@Entity
public class ChildLine extends Line {
@ManyToOne
public ChildHeader getHeader();
}
Problem: I get the error message "Error: 'getLines()
' in 'ChildHeader
' clashes with 'getLines()
' in 'Header
'; attempting to use incompatible return type"
Attempted solution: Change List<Line>
to <T extends Line> List<T>
and List<ChildLine>
to <T extends ChildLine> List<T>
New Error: 'getLines()
' in 'ChildHeader
' clashes with 'getLines()
' in 'Header
'; both methods have same erasure, yet neither overrides the other
Attempted solution: Tried using Line[]
and ChildLine[]
instead of lists
New Error: "List/array has to be annotated with an @OrderColumn
(or @IndexColumn
)", but there is no ordering column. The order of the array doesn't matter, but seems like @OneToMany
or JPA is requiring one.
This is an impossible situation. What can I do?
答案1
得分: 1
自从ChildHeader的"getLines"没有覆盖Header的声明(考虑到它是一个抽象方法,最终必须完成),在所有意图上,您试图通过不同的返回类型重载该方法。
在Java中,这是不允许的。
有没有任何理由您不能像这样重写Header的"getLines"方法:
@Entity
public class ChildHeader extends Header {
@OneToMany
public List<Line> getLines();
// 由于这不是抽象类,所以应该在这里有一个实现
}
因为"ChildLine"扩展了"Line",所以您仍然可以返回一个仅包含"ChildLine"的列表。您只需要确保当调用这样的方法时,从Line列表中将这些"ChildLines"转移到ChildLine列表中。
类似的逻辑适用于线类。ChildLine试图通过确保它们的返回类型匹配来重载"getHeader()"方法,这将更容易实现。
英文:
Since ChildHeader's "getLines" isn't overriding Header's declaration (which, given it's an abstract method, will eventually have to be done), for all intents and purposes, you're attempting to overload the method by different return types.
In Java, that's not allowed.
Is there any reason you can't just override Header's "getLines" method like so:
@Entity
public class ChildHeader extends Header{
@OneToMany
public List<Line> getLines();
// since this isn't an abstract class, there
// should be an implementation here
}
Since "ChildLine" extends "Line", you could still return a list that has nothing but "ChildLine's". You'll just need to ensure that when such a method is called, those "ChildLines" from the Line list are transferred to a ChildLine List.
Similar logic applies to the line class. ChildLine is attempting to overload "getHeader()" from Line when it would be easier to override the method by making sure their return types match.
答案2
得分: 1
> „…这是一个不可能的情况…“
如果您遵循JLS关于重写实例方法的指导…
> ### 8.4.8.1. 重写(由实例方法进行)
>
> 在类C
中声明或继承的实例方法m
C
,如果满足以下所有条件,则从C
中**重写来自A
的另一个方法m
A
,该方法在类A
中声明:
>
> …
>
> * 方法m
C
的签名是方法m
A
的子签名(§8.4.2)。
>
> …
要特别注意关于方法签名的部分…
> ### 8.4.2. 方法签名
>
> 如果两个方法或构造函数M
和N
具有相同的签名,则它们具有相同的名称,相同的类型参数(如果有的话)(§8.4.4),并且在将N
的形式参数类型调整为M
的类型参数后,具有相同的形式参数类型…
您遇到错误的关键在于您的方法不符合JLS的标准。
> „…我能做什么?…“
如果您重构了您的*Header
*类…
public abstract class Header {
public abstract < L extends Line > List< L > getLines( );
}
并且如果您重构了您的*ChildHeader
*类…
public class ChildHeader extends Header {
@Override
@SuppressWarnings("unchecked")
public < C extends Line > List< C > getLines(){ … }
}
那么您可以执行我在这个可工作示例中演示的操作…
…
Header header = new ChildHeader( );
List< ChildLine > lines = header.getLines( );
ChildHeader childHeader = lines.get( 0 ).getHeader( );
…
英文:
> „…This is an impossible situation…“
Not if you follow the JLS' guidance on overriding instance methods…
> ### 8.4.8.1. Overriding (by Instance Methods)
>
> An instance method m
<sub>C
</sub> declared in or inherited by class C
, overrides from C
another method m
<sub>A
</sub> declared in class A
, iff all of the following are true:
>
> …
>
> * The signature of m
<sub>C
</sub> is a subsignature (§8.4.2) of the signature of m
<sub>A
</sub>.
>
> …
>
Pay particular attention to the section on method signatures…
> ### 8.4.2. Method Signature
>
> Two methods or constructors, M
and N
, have the same signature if they have the same name, the same type parameters (if any) (§8.4.4), and, after adapting the formal parameter types of N
to the the type parameters of M
, the same formal parameter types…
The crux of the errors you got is because your methods don't meet the JLS's criteria.
> „…What can I do?…“
If you refactored your Header
class…
public abstract class Header {
public abstract < L extends Line > List< L > getLines( );
}
And if you refactored your ChildHeader
class…
public class ChildHeader extends Header {
@Override
@SuppressWarnings("unchecked")
public < C extends Line > List< C > getLines(){ … }
}
Then you could do what I demonstrate in this working example…
…
Header header = new ChildHeader( );
List< ChildLine > lines = header.getLines( );
ChildHeader childHeader = lines.get( 0 ).getHeader( );
…
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论