Bonjour,

Voici le problème :
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
53
54
55
56
 
java.lang.IllegalStateException: Primary key for object of type Categories is null.
	at org.datanucleus.store.appengine.EntityUtils.getPkAsKey(EntityUtils.java:152)
	at org.datanucleus.store.appengine.DatastoreFieldManager.getKeyForObject(DatastoreFieldManager.java:625)
	at org.datanucleus.store.appengine.DatastoreFieldManager.getParentKeyFromParentField(DatastoreFieldManager.java:634)
	at org.datanucleus.store.appengine.DatastoreFieldManager.establishEntityGroup(DatastoreFieldManager.java:591)
	at org.datanucleus.store.appengine.DatastorePersistenceHandler.insertPreProcess(DatastorePersistenceHandler.java:343)
	at org.datanucleus.store.appengine.DatastorePersistenceHandler.insertObjects(DatastorePersistenceHandler.java:251)
	at org.datanucleus.store.appengine.DatastorePersistenceHandler.insertObject(DatastorePersistenceHandler.java:240)
	at org.datanucleus.state.JDOStateManagerImpl.internalMakePersistent(JDOStateManagerImpl.java:3185)
	at org.datanucleus.state.JDOStateManagerImpl.makePersistent(JDOStateManagerImpl.java:3161)
	at org.datanucleus.ObjectManagerImpl.persistObjectInternal(ObjectManagerImpl.java:1298)
	at org.datanucleus.ObjectManagerImpl.persistObject(ObjectManagerImpl.java:1175)
	at org.datanucleus.jdo.JDOPersistenceManager.jdoMakePersistent(JDOPersistenceManager.java:669)
	at org.datanucleus.jdo.JDOPersistenceManager.makePersistent(JDOPersistenceManager.java:694)
	at be.jrousseau.gwtsite.server.dao.implementations.CompetencesDaoImpl.save(CompetencesDaoImpl.java:51)
	at be.jrousseau.gwtsite.server.controllers.CompetencesController.doPost(CompetencesController.java:69)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at com.google.appengine.tools.development.agent.runtime.Runtime.invoke(Runtime.java:100)
	at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:174)
	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:421)
	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:409)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:771)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:716)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:560)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:713)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:806)
	at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
	at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:51)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
	at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
	at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:122)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
	at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
	at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
	at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
	at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
	at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
	at com.google.apphosting.utils.jetty.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:70)
	at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
	at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:349)
	at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
	at org.mortbay.jetty.Server.handle(Server.java:326)
	at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
	at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:938)
	at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:755)
	at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
	at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
	at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
	at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
Le contrôleur :
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
53
 
@Controller
@RequestMapping("/admin/competences")
public class CompetencesController {
	private CategoriesDao categoriesDao;
	private CompetencesDao competencesDao;
 
	@Autowired
	public CompetencesController(CategoriesDao categoriesDao, CompetencesDao competencesDao){
		this.categoriesDao = categoriesDao;
		this.competencesDao = competencesDao;
	}
 
	@RequestMapping(method = RequestMethod.GET)
	public ModelAndView doGet(){
		ModelAndView mav = new ModelAndView("admin_competences");
		List<Categories> categories = this.categoriesDao.getAll();
		mav.addObject("categories", categories);
		Competences competences = new Competences();
		competences.setCategory(null);
		mav.addObject(competences);
		return mav;
	}
 
	@InitBinder
	public void initDataBinder(WebDataBinder binder, HttpServletRequest req) {
		binder.setDisallowedFields("category");
		Competences comp = (Competences)binder.getTarget();
		if(req.getParameter("category") != null){
			comp.setCategory(this.categoriesDao.getById(req.getParameter("category")));
		}
	}
 
	@RequestMapping(method = RequestMethod.POST)
	public ModelAndView doPost(Competences competences, BindingResult bindingResult){
		ModelAndView mav = new ModelAndView("admin_competences");
		if (bindingResult.hasErrors()) {
			mav.addObject("listErrors",bindingResult.getAllErrors());
			mav.getModel().putAll(bindingResult.getModel());
	    } else {
			if(competences.getCategory() == null){
				mav.addObject("error", "NULL");
			} else {
				mav.addObject("error", competences.getCategory().getKey().toString()
						+ " " + competences.getCategory().getName());
			}
			this.competencesDao.save(competences);
	    }
		List<Categories> categories = this.categoriesDao.getAll();
		mav.addObject("categories", categories);
		return mav;
	}
}
Categories :
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
 
@PersistenceCapable
public class Categories {
 
	@PrimaryKey
	@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
	private Key key;
 
	@Persistent
	private String name;
 
	@Persistent(mappedBy="category")
	@Element(dependent="true")
	private List<Competences> competences;
 
	public Categories(){
		this.competences = new ArrayList<Competences>();
	}
 
	public String getName() {
		return name;
	}
 
	public void setName(String name) {
		this.name = name;
	}
 
	public List<Competences> getCompetences() {
		return competences;
	}
 
	public void setCompetences(List<Competences> competences) {
		this.competences = competences;
	}
 
	public Key getKey() {
		return key;
	}
 
	public String getKeyToString(){
		return KeyFactory.keyToString(this.key);
	}
 
	public void setKey(Key key){
		this.key = key;
	}
}
Competences :
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
53
54
55
56
57
 
@PersistenceCapable
public class Competences {
 
	@PrimaryKey
	@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
	private Key key;
 
	@Persistent
	private String name;
 
	@Persistent
	private int level;
 
	@Persistent
	private Categories category;
 
	public Competences(){
 
	}
 
	public String getName() {
		return name;
	}
 
	public void setName(String name) {
		this.name = name;
	}
 
	public int getLevel() {
		return level;
	}
 
	public void setLevel(int level) {
		this.level = level;
	}
 
	public Categories getCategory() {
		return category;
	}
 
	public void setCategory(Categories category) {
		this.category = category;
	}
 
	public Key getKey() {
		return key;
	}
 
	public String getKeyToString(){
		return KeyFactory.keyToString(this.key);
	}
 
	public void setKey (Key key){
		this.key = key;
	}
}
Et le DAO qui devrait faire le makePersistent :
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
 
public class CompetencesDaoImpl implements CompetencesDao {
	PersistenceManagerFactory pmf;
 
	public CompetencesDaoImpl(){
 
	}
 
	@Override
	public void delete(String id) {
		PersistenceManager pm = pmf.getPersistenceManager();
		Competences comp = pm.getObjectById(Competences.class, KeyFactory.stringToKey(id));
		pm.deletePersistent(comp);
		pm.close();
	}
 
	@SuppressWarnings("unchecked")
	@Override
	public List<Competences> getAll() {
		PersistenceManager pm = pmf.getPersistenceManager();
		String query = "select from " + Competences.class.getName();
		List<Competences> competences = (List<Competences>)pm.newQuery(query).execute();
		competences = (List<Competences>) pm.detachCopyAll(competences);
		pm.close();
		return competences;
	}
 
	@Override
	public Competences getById(String id) {
		PersistenceManager pm = pmf.getPersistenceManager();
		Competences comp = pm.getObjectById(Competences.class, KeyFactory.stringToKey(id));
		comp = pm.detachCopy(comp);
		pm.close();
		return comp;
	}
 
	@Override
	public void save(Competences competence) {
		PersistenceManager pm = pmf.getPersistenceManager();
		pm.makePersistent(competence);
		pm.close();
	}
 
	public void setPmf(PersistenceManagerFactory pmf){
		this.pmf = pmf;
	}
 
}
Pourtant, la propriété "category" de mon objet "competences" contient bien un objet "Categories" valide, avec la Key et tout et tout, juste avant la sauvegarde ! Vérifié 2000 fois...

Une idée pour sauver les quelques cheveux qu'il me reste ?