Précédent   Forum des professionnels en informatique > Java > Général Java > Spring
Spring Forum d'entraide pour le framework Spring. Avant de poster -> FAQ Spring
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 25/01/2012, 14h16   #1
Membre régulier
 
Homme Lionel ANDRE
Inscription : avril 2005
Messages : 294
Détails du profil
Informations personnelles :
Nom : Homme Lionel ANDRE
Âge : 27
Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

Informations forums :
Inscription : avril 2005
Messages : 294
Points : 77
Points : 77
Par défaut Spring MVC : Collision entre plusieurs "@ModelAttributes" ayant des propriétés de même nom

Bonjour à tous,

Je viens de me rendre compte d'un gros problème avec Spring MVC.
J'ai un controlleur qui possède 2 méthodes annotées "@ModelAttribute" avec des classes différentes : "Project" et "Document".
C'est 2 classes possède (entre autre) les propriété "id" et "reference".

@ModelAttribute("project") est systématiquement appelé dans tous mes controlleurs "projet". Il récupère la référence du projet à partir de l'url et l'ajoute dans la session s'il est différent de celui déjà existant.

Lorsque je POST mon formulaire d'édition d'un document, je me retrouve du coup avec @ModelAttribute("project") et @ModelAttribute("document") qui se suivent.
Le problème c'est que ça génè-re des collisions : l'id de mon projet est égale à l'id du document, et la même chose pour la référence.

Un bug ? Une erreur ? Une mauvaise pratique ?

Comment corriger le problème ?
andlio est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 25/01/2012, 19h24   #2
Expert Confirmé
 
Homme
Inscription : septembre 2006
Messages : 2 291
Détails du profil
Informations personnelles :
Sexe : Homme

Informations forums :
Inscription : septembre 2006
Messages : 2 291
Points : 2 738
Points : 2 738
Version de Spring + le code pls.

A priori, je soupçonnerais un mélange de 2 @Controller multi-action et @ModelAttribute sur des méthodes.

S'il n'y a pas de @RequestMapping sur la classe @Controller, Spring ne peut sans doute pas limiter le scope des méthodes annotées @ModelAttribute.
JeitEmgie est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 25/01/2012, 22h30   #3
Membre régulier
 
Homme Lionel ANDRE
Inscription : avril 2005
Messages : 294
Détails du profil
Informations personnelles :
Nom : Homme Lionel ANDRE
Âge : 27
Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

Informations forums :
Inscription : avril 2005
Messages : 294
Points : 77
Points : 77
Bonsoir,

J'utilise spring 3.0.5. Je n'ai pas le code sur moi, je le posterai demain matin à la 1ère heure.
En attendant voici l'architecture : J'ai eu classe abstraite AbstractProjectController, et une classe DocumentController qui hérite de AbstractProjectController.

Il y a plusieurs modules pour un projet, dont une base documentaire. Chaque controller d'un module de projet hérite de AbstractProjectController.

AbstractProjectController possède entre autre cette fameuse méthode qui est annotée "@ModelAttribute("project")" qui permet de récupérer le projet à partir d'une "path variable" de l'url.

Je n'ai jamais eu de problème jusqu'à présent, mais je n'avais pas le scénario d'avoir 2 propriétés de même nom pour 2 modèle attribute différent...
andlio est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 26/01/2012, 09h47   #4
Membre régulier
 
Homme Lionel ANDRE
Inscription : avril 2005
Messages : 294
Détails du profil
Informations personnelles :
Nom : Homme Lionel ANDRE
Âge : 27
Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

Informations forums :
Inscription : avril 2005
Messages : 294
Points : 77
Points : 77
Comme promis voici le code.

AbstractProjectController :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
public abstract class AbstractProjectController {
 
	@Autowired
	protected IProjectService projectSvc = null;
 
	@ModelAttribute(MODEL_ATTR_CURRENT_PROJECT)
	public Project getSessionCurrentProject(HttpServletRequest servletRequest){
 
		//...
		return sessionSelectedProject;
	}
}
DocumentController :
Code :
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
@Controller
@RequestMapping("/projects/{projectRef}/documents/{documentId}")
public class DocumentController extends AbstractProjectController {
 
	//...
 
	@ModelAttribute(ATT_KEY_DOCUMENT)
	public AbstractDocument populateDocument(HttpServletRequest servletRequest){
 
		//...
 
		return document;
	}
 
	//...
 
	@RequestMapping(value="/edit", method=RequestMethod.POST)
	public String processSubmitEditDocumentForm(
			ModelMap model,
			@ModelAttribute(MODEL_ATTR_CURRENT_PROJECT) Project currentProject,
			@ModelAttribute(ATT_KEY_DOCUMENT) SimpleDocument document,
			@PathVariable(PATH_VAR_PROJECT_REF) String projectRef,
			@PathVariable(PATH_VAR_DOCUMENT_ID) int documentId,
			HttpServletRequest servletRequest){
 
		/* Call the service */
		try {
			Project currentProject = getSessionCurrentProject(servletRequest);
			librarySvc.saveDocument(currentProject, document);
 
		} catch(Exception e){
			e.printStackTrace();
			model.addAttribute(ATT_KEY_MESSAGE_ERROR, e.getMessage());
			return VW_PROJECT_DOCUMENT_FORM;
		}
 
		return "redirect:/projects/" + projectRef + "/documents/" + documentId;
	}
}
andlio est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 26/01/2012, 13h38   #5
Expert Confirmé
 
Homme
Inscription : septembre 2006
Messages : 2 291
Détails du profil
Informations personnelles :
Sexe : Homme

Informations forums :
Inscription : septembre 2006
Messages : 2 291
Points : 2 738
Points : 2 738
vous avez 2 fois @ModelAttribute(MODEL_ATTR_CURRENT_PROJECT)… donc il est appelé 2 fois…

si vous avez une méthode @ModelAttribute(MODEL_ATTR_CURRENT_PROJECT), il ne faut rajouter un paramètre, en principe la méthode suffit…

et si vous faites @Controller avec @RequestMapping, j'éviterais de rajouter @RequestMapping sur une méthode de ce controller pour changer l'URL, mais uniquement pour préciser method=RequestMethod
JeitEmgie est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 27/01/2012, 14h25   #6
Membre régulier
 
Homme Lionel ANDRE
Inscription : avril 2005
Messages : 294
Détails du profil
Informations personnelles :
Nom : Homme Lionel ANDRE
Âge : 27
Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

Informations forums :
Inscription : avril 2005
Messages : 294
Points : 77
Points : 77
Bonjour JeitEmgie,

Effectivement je n'ai plus ce phénomène de collision si je commente "@ModelAttribute(MODEL_ATTR_CURRENT_PROJECT) Project currentProject," dans DocumentController.processSubmitEditDocumentForm(), et que j'utilise "Project project = (Project) model.get(MODEL_ATTR_CURRENT_PROJECT);" à la place.

Pourtant je pensais que c'était équivalent. J'ai vérifié avec des points d'arrêt, et la méthode annotée "@ModelAttribute(MODEL_ATTR_CURRENT_PROJECT)" est appelée 2 fois dans tous les cas.
Sauf que si je mets "@ModelAttribute(MODEL_ATTR_CURRENT_PROJECT) Project currentProject" dans les paramètres alors qu'il y a déjà un "@ModelAttribute" avec une autre classe ayant des nom propriétés identiques, alors Spring prend les valeurs soumises par le modelAttribute du formulaire....

Est-ce normal ? Existe-t-il un moyen d'y remédié ?
andlio est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 00h39.


 
 
 
 
Partenaires

Hébergement Web