Bonjour à tous,
Je souhaiterais avoir votre avis sur le problème suivant :
A modéliser : tâches ayant plusieurs sous tâches et une tâche parente.
JPA :
Une première classe sert uniquement pour l'id.
Je ne mets pas volontairement les getters et les setters pour la lisibilité.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 public class BaseEntity { private Integer id; }
Une tâche :
La config :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 public class Task extends BaseEntity { private Date time; private String name; private BaseEntity parent; private Set<BaseEntity> enfants; }
EJB/WS :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 [...] <entity class="BaseEntity"> <attributes> <id name="id"> <generated-value strategy="IDENTITY" /> </id> <transient name="new" /> </attributes> </entity> <entity class="Task"> <attributes> <basic name="time"> <temporal>TIME</temporal> </basic> <basic name="name"></basic> <many-to-one name="parent" target-entity="BaseEntity" fetch="LAZY" /> <one-to-many name="enfants" target-entity="BaseEntity"> <cascade> <cascade-all/> </cascade> </one-to-many> </attributes> </entity> [...]
Petite subtilité : getAll renvoie un Task[] pour pouvoir être une WebMethod.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 @Stateless @TransactionAttribute(TransactionAttributeType.REQUIRED) @WebService(name="ProjectTest", serviceName="ServiceProject") @SOAPBinding(style=Style.RPC) public class ServiceProject { @EJB private IDaoProject dao; @WebMethod public Task[] getAll() { List<Task> tasks = dao.getAll(); return tasks.toArray(new Task[0]); } }
Une fois que tout est déployé, j'obtiens le wsdl suivant (via l'adresse http://localhost:8080/[dossier de déploiement]/ServiceProject?wsdl) :
(à peu prêt, j'ai taillé dans mon wsdl)
Et maintennant, si je remplis ma base avec une arborescence de tâches, je peux très bien appeler mon service depuis mon appli web, pour retrouver la liste des tâches. Les enfants de ceux ci ne sont pas initialisés, mais j'ai des BaseEntity avec des id.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 <definitions name="ServiceProject" targetNamespace="http://service.test.org/" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://service.test.org/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <types> <xs:schema targetNamespace="http://service.test.org/" version="1.0" xmlns:tns="http://service.test.org/" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:complexType name="task"> <xs:complexContent> <xs:extension base="tns:baseEntity"> <xs:sequence> <xs:element maxOccurs="unbounded" minOccurs="0" name="enfants" nillable="true" type="tns:baseEntity"/> <xs:element minOccurs="0" name="name" type="xs:string"/> <xs:element minOccurs="0" name="parent" type="tns:baseEntity"/> <xs:element minOccurs="0" name="time" type="xs:dateTime"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="baseEntity"> <xs:sequence> <xs:element minOccurs="0" name="id" type="xs:int"/> </xs:sequence> </xs:complexType> <xs:complexType final="#all" name="taskArray"> <xs:sequence> <xs:element maxOccurs="unbounded" minOccurs="0" name="item" nillable="true" type="tns:task"/> </xs:sequence> </xs:complexType> </xs:schema> </types> <message name="ProjectTest_getAll"/> <portType name="ProjectTest"> <operation name="getAll"> <input message="tns:ProjectTest_getAll"/> <output message="tns:ProjectTest_getAllResponse"/> </operation> </portType> <binding name="ProjectTestBinding" type="tns:ProjectTest"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="getAll"> <soap:operation soapAction=""/> <input> <soap:body namespace="http://service.test.org/" use="literal"/> </input> <output> <soap:body namespace="http://service.test.org/" use="literal"/> </output> </operation> </binding> <service name="ServiceProject"> <port binding="tns:ProjectTestBinding" name="ProjectTestPort"> <soap:address location="http://127.0.0.1:8080/simexplorer-si-template-ejb/ServiceProject"/> </port> </service> </definitions>
Mais si j'appelle getAll en WS, l'appel à mon service va bien se passer, mais lorsque la librairie construit le résultat pour le client, elle va chercher à instancier toute l'arborescence. Et puisqu'on est sorti de la méthode du service (où mon contexte transactionnel me permet le chargement JPA), on a une LazyException.
Le deuxième problème qui est apparu, c'est que lorsque le parent d'un enfant est remonté pour la réponse, il retrouve la même instance. Il constate la récursivité que cela impliquerait et s'arrête.
Pour palier à ce problème, j'ai essayé de passer le parent et les enfants en BaseEntity, pour renvoyer uniquement les ids. Mais l'instance de parent est bien une Task, et le WS l'"introspecte" quand même...
Si vous voyez une issue, je suis preneur
Merci
Partager