-1

I am using Guice with JDO and Datanucleus in my desktop app. I am facing a NPE that I can't fix, so I hope someone can help me :)

I am using properly configured H2 db, with schema created and all my classes are nicely enhanced, so it's not that. Anyway, I am getting NPE here, at JDORepository class:

public abstract class JdoRepository<T> implements Repository<T>
{
private final Class<T> clazz;
private final Provider<PersistenceManager> pmProvider;

protected JdoRepository(Class<T> clazz, Provider<PersistenceManager> pmProvider)
{
    this.clazz = clazz;
    this.pmProvider = pmProvider;
}
public void persist(T entity)
{
    pmProvider.get().makePersistent(entity);   <---- NPE!
}

My PersistenceManagerFilter looks like that:

    @Singleton
    public class PersistenceManagerFilter implements Filter
    {
    private static final Logger logger =  Logger.getLogger(PersistenceManagerFilter.class.getName());

    private static final ThreadLocal<PersistenceManager> pm = new  ThreadLocal<PersistenceManager>();

    private PersistenceManagerFactory pmf;

    public void init(FilterConfig filterConfig) throws ServletException
    {
        logger.info("Creating PersistenceManagerFactory");
        pmf = JDOHelper.getPersistenceManagerFactory();
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain  chain)
            throws IOException, ServletException
    {
        try
        {
            pm.set(pmf.getPersistenceManager());
            chain.doFilter(request, response);
        }
        finally
        {
            pm.get().close();
        }
    }

    public void destroy()
    {
        logger.info("Closing PersistenceManagerFactory");
        pmf.close();
    }

    /**
     * This module binds the JDO {@link javax.jdo.PersistenceManager} interface to the  provider that allows the
     * implementation to be injected as Provider&lt;PersistenceManager&gt;.
     */
    public static class GuiceModule extends AbstractModule
    {
        @Override
        protected void configure()
        {
            bind(PersistenceManager.class).toProvider(new Provider<PersistenceManager>()
            {
                public PersistenceManager get()
                {
                    return PersistenceManagerFilter.pm.get();
                }
            });
        }
    }
}

And the responsible module:

    public class GuiceModule extends AbstractModule
   {
   @Override
   protected void configure()
   {
       // Enable per-request-thread PersistenceManager injection.
       install(new PersistenceManagerFilter.GuiceModule());
       bind(new TypeLiteral<Repository<Project>>() { }).to(JdoProjectRepository.class);

I am initiating it all that way:

Injector injector = Guice.createInjector(new GuiceModule());
    Main main = injector.getInstance(Main.class);
    main.run();

So repository bindings in main class work fine, as they are redirected to JDORepository. It's something at lower level, PMF not getting bound properly? Any ideas?

Paul
  • 389
  • 3
  • 11

1 Answers1

1

What does your main.run()-method do? Does it call PersistenceManagerFilter#doFilter? If it doesn't, the value in yourThreadLocal<PersistenceManager> will be null...

You could override the initialValue() and do something like this:

ThreadLocal<PersistenceManager> pm = new  ThreadLocal<PersistenceManager>(){
    @Override
    protected PersistenceManager initialValue() {
        return JDOHelper.getPersistenceManagerFactory().getPersistenceManager();
    }
};

You should also remember to call the ThreadLocal#remove() method in your finally-block.

Instead of handling the ThreadLocal yourself, you could bind the PersistenceManager directly in the guice-module:

class GuiceModule extends AbstractModule {

    @Provides @RequestScoped
    PersistenceManager providePersistenceManager(){
        return JDOHelper.getPersistenceManagerFactory().getPersistenceManager();
    }

    @Override
    protected void configure() {}
}
eiden
  • 2,329
  • 19
  • 19
  • Nope, I didn't add anything like it to my run() method. All I have is – Paul Jan 18 '12 at 09:14
  • Nope, I didn't add anything like it to my run() method. All I have is @Inject public Repository projectRepo; ... projectRepo.persist(newProject); I don't really know what to add where :) I guess that adding any of your code would require some replacing. And RequestScoped is not basic annotation. Hmm... what would you add to main.run() then? – Paul Jan 18 '12 at 09:22
  • Sorry, I just assumed that you were using the 'guice-servlet'-extension. The @RequestScoped annotation is provided by that extension. In your code, you set the value in the `ThreadLocal` in the `doFilter`. Either call `doFilter` from `main#run()` or override the `initialValue()` in the `ThreadLocal` – eiden Jan 18 '12 at 10:03
  • I still can't solve that, what to put where. I admit that it's a bit complicated stuff :) For running doFilter I'd have to invoke it with service, request and chain, so it'd be quire inconvenient. Where should I put that override of initialValue in ThreadLocal? – Paul Jan 18 '12 at 12:51
  • Hmm... I don't think calling doFilter is the problem. I will still get NPE at pm.get() while doing it. So problem is probably somewhere else. NPE will be here: finally { pm.get().close(); } – Paul Jan 18 '12 at 21:11
  • How did you reach that conclusion? You set the value in the ThreadLocal 5 lines above that call. Are you sure that your PersistenceManagerFactory#getPersistenceManager() doesn't return null? – eiden Jan 19 '12 at 09:40
  • Hmm... in which class should I add that ThreadLocal code? I think that PersistenceManagerFactory#getPersistenceManager() does indeed return null. – Paul Jan 19 '12 at 10:19
  • If PersistenceManagerFactory#getPersistenceManager() return null, that's the first problem you have to fix. Try adding the 'ThreadLocal code' to your PersistenceManagerFilter. Good luck. – eiden Jan 19 '12 at 10:42