Domanda da ex-cpiùpiùista sull'ereditarietà multipla

8 views
Skip to first unread message

mick...@posteo.net

unread,
Apr 5, 2022, 11:03:49 AM4/5/22
to Java User Group TAA
A voi guru di Java e design-pattern!

Contesto: abbiamo implementato un servizio rest le cui api rispondono
con dei json che anno alcuni campi in comune (tipo l'esito
dell'operazione). Quindi abbiamo definito una super-classe con campi (e
accessor) in comune (chiamiamola S), che ognuna delle classi da
serializzare in json, deriva, aggiungendo le informazioni specifiche.

Ora però mi trovo di fronte ad un dilemma: 2 API restituiscono
rispettivamente un oggetto singolo e una lista di oggetti, tutti dello
stesso tipo.

In C++ sfrutterei l'ereditarietà multipla: definirei una classe A con le
sole informazioni dell'oggetto, una classe V che deriva dalla
superclasse S e che contiene una lista di A, e una classe W che eredita
da S ed anche da A (e quindi rappresenta l'oggetto singolo).

In java inizialmente l'avrei pensata così:
Dichiaro una interfaccia al posto della superclasse S, con 2 membri e
gli getter/setter dotati di implementazione di default; poi dichiaro A,
dichiaro V che implementa S, e W che deriva da A ed implementa S
(entrambe che facciano affidamento ai metodi di default).
Tuttavia non si può! I membri non possono essere private (il minore dei
problemi), ma soprattutto i metodi di default non possono fare
riferimento ai membri.

Per sbrogliare la questione mi trovo di fronte a tre strade:
1. duplico le informazioni di A in W
2. definisco S come interfaccia, in cui dichiaro getter/setter, e
duplico membri ed implementazione di getter/setter in ogni oggetto da
serializzare.
3. definisco una interfaccia IS, la superclasse S che implementa IS, e
duplico l'implementazione di IS solo nella classe W (che quindi deriva
da A e implementa IS).

Quale di queste (o altre) si avvicina alla best-practice?

Domanda più praticona: nei casi 2/3, come dichiaro IS in modo che
jackson serializzi i getter? (non so se sono stato chiaro)

Buona serata
--
Mick

Chris Mair

unread,
Apr 5, 2022, 11:15:03 AM4/5/22
to jug...@googlegroups.com

> Ora però mi trovo di fronte ad un dilemma: 2 API restituiscono rispettivamente un oggetto singolo e una lista di oggetti, tutti dello stesso tipo.
> [...]
> Quale di queste (o altre) si avvicina alla best-practice?

Magari dico una stupidita, ma la butto li`?

Non puoi vederlo come oggetto e ArrayList<oggetto> e sfruttare
il fatto che Jackson mappa anche List e Map oltre che gli oggetti?

Bye,
Chris.




Andrea Selva

unread,
Apr 5, 2022, 11:19:50 AM4/5/22
to jug...@googlegroups.com
Da come l'ho letta, se capisco bene la tua necessità è che la "lista di S" derivi da S a sua volta. Quindi ci sarebbe la super classe S che riporta la stato comune, una classe collection che subclassa S e che può contenere altri S.
Forse potresti usare il composite pattern.

 Andrea

--
You received this message because you are subscribed to the Google Groups "JUG Trentino Alto Adige Suedtirol" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jugtaa+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/jugtaa/cfc6aa19cff85a38f5c94627da997b01%40smtp.hushmail.com.

tia...@gmail.com

unread,
Apr 5, 2022, 12:35:04 PM4/5/22
to JUG Trentino Alto Adige Suedtirol
In teoria dovrebbe essere possibile simulare l'eredità multipla con composizione e @JsonUnwrapped:

record V(@JsonUnwrapped S s, @JsonUnwrapped A a) { }
record W(@JsonUnwrapped S s, List<A> listOfAs) { }

Funzionerebbe anche ereditare sempre da S e usare @JsonUnrwapped solo per A in V:

class V extends S { @JsonUnwrapped A a; }
class W extends S { List<A> listOfAs; }

Però tutto questo é solo teoria e non testato.

Matthias

mick...@posteo.net

unread,
Apr 6, 2022, 2:17:54 AM4/6/22
to jug...@googlegroups.com


On 05.04.2022 17:19, Andrea Selva wrote:
> On Tue, Apr 5, 2022 at 5:15 PM Chris Mair <ch...@1006.org> wrote:
>>
>> Non puoi vederlo come oggetto e ArrayList<oggetto> e sfruttare
>> il fatto che Jackson mappa anche List e Map oltre che gli oggetti?
>
> Da come l'ho letta, se capisco bene la tua necessità è che la "lista
> di S" derivi da S a sua volta. Quindi ci sarebbe la super classe S che
> riporta la stato comune, una classe collection che subclassa S e che
> può contenere altri S.
>
> Forse potresti usare il composite pattern.
>

Mi spiego meglio. Vorrei da un lato un json del tipo:
{
"esito": 0,
"messaggio": "tutto ok",
"info1": "",
"info2": "",
...
}

e dall'altra:
{
"esito": 0,
"messaggio": "tutto ok",
"lista":[{
"info1": "",
"info2": "",
...
},
{
"info1": "",
"info2": "",
...
},
{
"info1": "",
"info2": "",
...
},
...
]
}

Fino ad ora avevo una
class S {
private int esito;
private String messaggio;

// getter/setter
}

e una

class Info extends S {
private String info1;
...
}

Attualmente (per un refuso) la seconda API restituisce un Info[], ed è
sbagliato, perché il json deve avere esito e messaggio a livello base, e
non ripetuto per ogni elemento della lista.

Una soluzione veloce sarebbe definire:

class ListaInfo extends S {
List<Info> infos;
}

Personalmente la trovo poco elegante, ma è legata ad una mia personale
mania (ereditata dai tempi del C su dsp) di "ottimizzazione di tempi e
spazi" - vedi quegli esito/messaggio inutili negli elementi della lista.

Quello che vorrei evitare è definire

class Info extends S {...}

e

class InfoEntry {...}

perfettamente identiche, a parte la superclasse.
--
Mick

Chris Mair

unread,
Apr 6, 2022, 4:07:20 AM4/6/22
to jug...@googlegroups.com
>
> Mi spiego meglio. Vorrei da un lato un json del tipo:
> {
> "esito": 0,
> "messaggio": "tutto ok",
> "info1": "",
> "info2": "",
> ...
> }
>
> e dall'altra:
> {
> "esito": 0,
> "messaggio": "tutto ok",
> "lista":[{
> "info1": "",
> "info2": "",
> ...
> },
> {
> "info1": "",
> "info2": "",
> ...
> },
> {
> "info1": "",
> "info2": "",
> ...
> },
> ...
> ]
> }
>

[...]


E se facessi finta di avere solo il secondo caso, anche se lista contiene solo *un* elemento (cosi` e` immediato
come object mapping) e usassi in qualche modo questo:

https://fasterxml.github.io/jackson-databind/javadoc/2.6/com/fasterxml/jackson/databind/SerializationFeature.html#WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED

"if enabled, Collections and arrays that contain exactly one element will be serialized as if that element itself was serialized. "


Bye,
Chris.


mick...@posteo.net

unread,
Apr 7, 2022, 2:17:13 AM4/7/22
to jug...@googlegroups.com
On 05.04.2022 18:35, tia...@gmail.com wrote:
> In teoria dovrebbe essere possibile simulare l'eredità multipla con
Funzionerebbe anche ereditare sempre da S e usare @JsonUnrwapped solo
> per A in V:
>
> class V extends S { @JsonUnwrapped A a; }
> class W extends S { List<A> listOfAs; }
>
> Però tutto questo é solo teoria e non testato.
>
Confermo, questo funziona. Per riportare la soluzione rispetto
all'ultimo esempio, ecco cosa ho fatto:

class S {...}
class InfoEntry {...}
class InfoList extends S {
List<InfoEntry> infos;
}
class InfoSingle extends S {
@JsonUnwrapped InfoEntry info;
}

Il risultato è che nella serializzazione di InfoSingle, vengono
riportati i campi di InfoEntry inline.

Grazie a tutti!
--
Mick

Reply all
Reply to author
Forward
0 new messages