Jarrod Roberson Jarrod Roberson - 5 months ago 26
Java Question

How to automatically register @Entity decorated classes at application start up?

How you do enable Objectify to automatically discover your annotated
Entity
classes at runtime?



I want to register my classes at application start up and not have to hard code them into a class as recommended in the documentation.

Answer

Solution

This is no runtime reflection cost solution:

import com.google.appengine.api.ThreadManager;
import com.googlecode.objectify.ObjectifyFactory;
import com.googlecode.objectify.ObjectifyService;
import com.googlecode.objectify.annotation.Entity;
import org.reflections.Reflections;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * This class processes the classpath for classes with the @Entity or @Subclass annotations from Objectify
 * and registers them with the ObjectifyFactory, it is multi-threaded and works very fast!
 */
public class ObjectifyLoaderContextListener implements ServletContextListener
{
    private static final Logger L = LoggerFactory.getLogger(ObjectifyLoaderContextListener.class);

    private final Set<Class<?>> entities;

    public ObjectifyLoaderContextListener()
    {
        this.entities = new HashSet<>();
    }

    @Override
    public void contextInitialized(@Nonnull final ServletContextEvent sce)
    {
        final ConfigurationBuilder cb = new ConfigurationBuilder();
        cb.setUrls(ClasspathHelper.forPackage(""));
        final ExecutorService es = Executors.newCachedThreadPool(ThreadManager.currentRequestThreadFactory());
        cb.setExecutorService(es);
        final Reflections r = new Reflections(cb);
        this.entities.addAll(r.getTypesAnnotatedWith(Entity.class));
        es.shutdown();
        final ObjectifyFactory of = ObjectifyService.factory();
        for (final Class<?> cls : this.entities)
        {
            of.register(cls);
            L.debug("Registered {} with Objectify", cls.getName());
        }
    }

    @Override
    public void contextDestroyed(@Nonnull final ServletContextEvent sce)
    {
        /* this is intentionally empty */
    }
}

Updates to this class will be available in this gist.

Comments