Когда вы регистрируете классы в Objectify для GAE?

Так что это может быть глупый вопрос, но когда вы регистрируете классы с помощью:

ObjectifyService.register( User.class );

В настоящее время я делаю это в конструкторе класса, похожего на интерфейс, который я использую в других своих классах, чтобы упростить использование хранилища данных конкретно для моего приложения. Однако я получаю эту ошибку:

Попытка регистрации типа «Пользователь» дважды

Итак, я думаю, мой вопрос заключается в том, как часто и когда вы регистрируете классы в Objectify?

Спасибо!

P.S. Вот весь мой класс:

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Iterator;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.persistence.Id;

import com.googlecode.objectify.Objectify;
import com.googlecode.objectify.ObjectifyService;
import com.googlecode.objectify.annotation.Indexed;
import com.googlecode.objectify.annotation.Unindexed;

public class UsersService {

    Objectify ojy;

    public UsersService(){
        ObjectifyService.register( User.class );
        ojy = ObjectifyService.begin();
    }

    public void regUser(String email, String password, String firstName, String lastName){
        //TODO: Check syntax if email
        //TODO: store encrypted password
    }

    public void regUser(String email, String password, String firstName){
        regUser(email, password, firstName, null);
    }

    public void regUser(String email, String password){
        regUser(email, password, "", "");
    }

    public boolean checkFor(Long acc_id){
        User checked_user = ojy.find(User.class, acc_id);
        if(checked_user == null){
            return false;
        }else{
            return true;
        }
    }

    public User getUser(String email, String password) throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException{
        String pass_enc = MyUtils.getEncrypted(password);
        Iterable<User> users = ojy.query(User.class).filter("email", email).filter("password", pass_enc);
        Iterator<User> iter = users.iterator();
        if(iter.hasNext()){
            return iter.next();
        }else{
            return null;
        }
    }

}

person Brandon    schedule 04.11.2011    source источник


Ответы (3)


Обновить

Вот лучшее практическое решение:

Используйте свою собственную службу. Это гарантирует, что ваши объекты будут зарегистрированы до использования Objectify, но не обязательно влияет на запуск приложения для запросов, которые не обращаются к хранилищу данных.

import com.googlecode.objectify.Objectify;
import com.googlecode.objectify.ObjectifyFactory;
import com.googlecode.objectify.ObjectifyService;


public class OfyService {
    static {
        ObjectifyService.register(User.class);
    }

    public static Objectify ofy() {
        return ObjectifyService.begin();//prior to v.4.0 use .begin() , 
                                        //since v.4.0  use ObjectifyService.ofy();
    }

    public static ObjectifyFactory factory() {
        return ObjectifyService.factory();
    }

}

Затем используйте его следующим образом:

public User createUser(User pUser) {

    Objectify objectify = OfyService.ofy();
    objectify.put(pUser);

    return pUser;
}

Оригинальный ответ (лучше использовать код выше):

вы должны сделать это в своем классе, просто поместите статический блок следующим образом:

static{
    ObjectifyService.register( User.class );
}

p.s., вы тоже посмотрите на лучшие практики объективации

http://code.google.com/p/objectify-appengine/wiki/BestPractices

person Daniel    schedule 05.11.2011
comment
Спасибо. Я посмотрю и вернусь. - person Brandon; 05.11.2011
comment
Оно работает! Просто из любопытства, в чем разница между статическими блоками и конструкторами? - person Brandon; 05.11.2011
comment
статический блок выполняется один раз при загрузке класса (без создания объекта) для получения дополнительной информации: jusfortechies.com/java/core-java/static-blocks.php - person Daniel; 05.11.2011
comment
Спасибо! Это было действительно полезно. - person Brandon; 10.11.2011
comment
Objectify Best Practices не советует этого делать из-за непредсказуемости порядка загрузки Java-классов. - person out_sid3r; 14.04.2012
comment
@doubter Вы, должно быть, искали нужную страницу в НЕПРАВИЛЬНОМ месте... Так как пример в этом текущем вопросе говорит о DAO... Я привел пример того, как вы делаете это в DAO... code.google.com/p/objectify-appengine/wiki/ I не сказал разместить статический блок внутри класса User, вместо этого я сказал разместить его в классе, опубликованном в Вопросе... - person Daniel; 14.04.2012

Я использую аннотацию @Entity, библиотеку Reflections и регистрацию во время выполнения без существенного влияния на время запуска любого моих приложений, потому что вся информация собирается во время компиляции/сборки.

ObjectifyLoaderContextListener.java

package com.vertigrated.servlet;
 
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 uses a prebuilt list of classes to process
 * created by the Reflections library at compile time 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 */
    }
}
person Community    schedule 12.04.2015

Основываясь на ответе Дэни и на случай, если кто-то еще использует инъекцию зависимостей, я сделал это для Spring MVC и отлично сработал:

Я создал сервис следующим образом:

@Service
@Qualifier("objectifyService")
public class OfyService {
    static {
        ObjectifyService.register(GaeUser.class);
    }

    public static Objectify ofy() {
        return ObjectifyService.ofy();
    }

    public static ObjectifyFactory factory() {
        return ObjectifyService.factory();
    }

}

Затем, когда я хочу его использовать, я просто ввожу сервис следующим образом:

@Autowired
@Qualifier("objectifyService")
OfyService objectifyService;

И тогда я использую это так:

objectifyService.ofy().save().entity(user).now();
person Gemasoft    schedule 03.01.2016