Id annotation and RequestFactory

81 views
Skip to first unread message

Sydney

unread,
Jun 19, 2011, 12:19:22 PM6/19/11
to twig-p...@googlegroups.com
I was wondering if the behavior is different depending on the Id annotation used: com.google.code.twig.annotation.Id and javax.persistence.Id

I started to use Twig along with RequestFactory and an entity proxy needs an ID. I followed an example but written with Objectify, and tried to do the same but with Twig. All the domain object extends a DatastoreObject that handles the id and the version. With objectify javax.persistence.Id is fine but it seems that with Twig I need to use the specific Twig annotation. So far I was using javax.persistence.Id but my entities did not have any Id when editing them, so I can't call associate or update on them. So now I am trying to use the Twig specific annotation to see if it fixes the problem.



Does anybody use RequestFactory with Twig?


John Patterson

unread,
Jun 19, 2011, 9:35:32 PM6/19/11
to twig-p...@googlegroups.com
Hey Sydney, I have not used request factory but it looks very interesting and I'll have a deeper look at it later in my current project.  Yes you are right that Twig only looks for its own annotations and not javax.persistence.*.  I believe the Objectify guys have some problems with the choice to support them:
  1. You need to depend on an extra jar (geronimo)
  2. Configuration requires a mix of @s from two packages meaning it is hard to see which @s are actually available.
  3. We can add a field to twigs @s but not to the javax version
  4. It gives people the impression that the datastore is similar to JDO or others.
That said, it would be very easy to add support for them by extending AnnotationConfiguration.  So for example, instead of changing the annotations to use Twig, you could have created your ObjectDatastore like this:

public class SydneysObjectDatastore extends StandardObjectDatastore
{
    public SydneysObjectDatastore()
    {
        super(new AnnotationConfiguration()
        {
              public boolean id(Field field)
              {
                    return field.isAnnotationPresent(javax.persistence.Id.class) || super.id(field);
              }
        });

Mihail Lesikov

unread,
Jun 20, 2011, 2:45:45 AM6/20/11
to twig-p...@googlegroups.com
Hi,
we use twig and gwt request factory like that:

@Id
Long id;



Sydney

unread,
Jun 21, 2011, 12:46:47 PM6/21/11
to twig-p...@googlegroups.com
My TwigLocator looks like the same as Mihail's one. So I just want to confirm that you need to use the specific Twig annotation with the default ObjectDatastore configuration. Using RF with Twig is pretty easy to do. The only problem I had was related to Guice. A link of interest: https://github.com/etiennep/injected-requestfactory

I have one question though: Does Twig handle @PrePersist annotation?

    /**
     * Auto-increment version # whenever persisted
     */
    @PrePersist
    void onPersist() {
        this.version++;
    }

John Patterson

unread,
Jun 21, 2011, 1:52:59 PM6/21/11
to twig-p...@googlegroups.com
On 21/06/2011 23:46, Sydney wrote:
> My TwigLocator looks like the same as Mihail's one. So I just want to
> confirm that you need to use the specific Twig annotation with the
> default ObjectDatastore configuration. Using RF with Twig is pretty
> easy to do.

Good to hear


> The only problem I had was related to Guice. A link of interest:
> https://github.com/etiennep/injected-requestfactory
>
> I have one question though: Does Twig handle @PrePersist annotation?
>

No, it only looks for its own annotations. Is this really useful? I
normally do all work on the data models in a manager (DAO) class rather
than mixing it into the model also.

Sydney

unread,
Jun 23, 2011, 11:33:53 PM6/23/11
to twig-p...@googlegroups.com
While going forward with RequestFactory, I got an exception when storing my object:

java.lang.IllegalStateException: Key specification is incomplete.  You may need to define an id for instance with kind


I guess the exception is raised because the id is null. So I was wondering if there is a way to set the value to id automatically.

John Patterson

unread,
Jun 23, 2011, 11:41:44 PM6/23/11
to twig-p...@googlegroups.com
use @Entity(allocateIdsBy=100) on your data model class

Sydney

unread,
Jun 24, 2011, 12:14:25 AM6/24/11
to twig-p...@googlegroups.com
I added your annotation to DatastoreObject but now I get an exception

java.lang.NullPointerException
at com.google.code.twig.standard.StandardCommonStoreCommand.maybeSetAllocatedId(StandardCommonStoreCommand.java:290)
at com.google.code.twig.standard.StandardCommonStoreCommand.instanceToEntity(StandardCommonStoreCommand.java:251)
at com.google.code.twig.standard.StandardSingleStoreCommand.now(StandardSingleStoreCommand.java:51)
at com.google.code.twig.standard.TranslatorObjectDatastore.store(TranslatorObjectDatastore.java:144)

I debug your source and this is the line responsible for the NPE: KeyRange range = datastore.allocatedIdRanges.get(kindAndParent);

datastore.allocatedIdRanges is null

John Patterson

unread,
Jun 24, 2011, 2:08:43 AM6/24/11
to twig-p...@googlegroups.com
Ah this is a new feature and is only working in the latest source.  Sorry, should have mentioned that.

On 24 June 2011 11:14, Sydney <sydney....@gmail.com> wrote:

Sydney

unread,
Jun 24, 2011, 2:27:23 AM6/24/11
to twig-p...@googlegroups.com
So I grabbed the code from the mercurial and run a maven package. Is it normal the package starts with com.vercer instead of com.google.code.twig

John Patterson

unread,
Jun 24, 2011, 3:05:44 AM6/24/11
to twig-p...@googlegroups.com

Sydney

unread,
Jun 24, 2011, 7:21:38 PM6/24/11
to twig-p...@googlegroups.com
I got an exception. BTW there is a typo on the exception description.
java.lang.IllegalStateException: Dectected use by more than one thread
	at com.google.code.twig.standard.StandardCommand.<init>(StandardCommand.java:12)
	at com.google.code.twig.standard.StandardFindCommand.<init>(StandardFindCommand.java:9)
	at com.google.code.twig.standard.TranslatorObjectDatastore.find(TranslatorObjectDatastore.java:145)
	at com.google.code.twig.standard.TranslatorObjectDatastore.find(TranslatorObjectDatastore.java:209)
when I call
List<Update> updates = asList(datastore.find(Update.class));
with
    protected List<T> asList(QueryResultIterator<T> rs) {
        List<T> list = new ArrayList<T>();
        while (rs.hasNext()) {
            list.add(rs.next());
        }
        return list;
    }


John Patterson

unread,
Jun 24, 2011, 10:27:02 PM6/24/11
to twig-p...@googlegroups.com
Thanks for the typo! The exception warns you that ObjectDatastore's are
not intended for concurrent use. Create a new one for every request or
unit of work. They are very light weight objects.

Sydney

unread,
Jun 24, 2011, 11:01:46 PM6/24/11
to twig-p...@googlegroups.com
You mentioned several times that you were using Guice to create a new ObjectDatastore. My current setup is the following:

public UpdateDao {
    @Inject
    public UpdateDao(final ObjectDatastore datastore) {
        super(datastore);
        System.out.println("New Instance " + datastore);
    }
}

public class AnnotationObjectDatastoreProvider implements
        Provider<ObjectDatastore> {
    public ObjectDatastore get() {
        ObjectDatastore datastore = new AnnotationObjectDatastore(false);
        return datastore;
    }
}

bind(ObjectDatastore.class).toProvider(AnnotationObjectDatastoreProvider.class);

So every where I need to do operations on a specific domain object, I inject the DAO. But I run in this concurrency exception. How is your setup?

John Patterson

unread,
Jun 24, 2011, 11:16:55 PM6/24/11
to twig-p...@googlegroups.com
On 25/06/2011 10:01, Sydney wrote:
> bind(ObjectDatastore.class).toProvider(AnnotationObjectDatastoreProvider.class);
>
> So every where I need to do operations on a specific domain object, I
> inject the DAO. But I run in this concurrency exception. How is your
> setup?
>

That looks fine - the question is how do you use your DAO? Is that also
scoped to NO_SCOPE? It seems from the error that a DAO is being held
onto and reused between requests.

I normally scope the OD to REQUEST so I can load objects in filters and
reuse later them without thinking about if they are associated or not.
But there are also cases where it makes sense to scope to NO_SCOPE like
you have to keep operations isolated.

Sydney

unread,
Jun 24, 2011, 11:48:22 PM6/24/11
to twig-p...@googlegroups.com
I think I found the reason why I got the exception.

I have a servlet defined as:

    @Inject
    public MyServlet(MyService service) {
        this.service = service;
        System.out.println(Thread.currentThread());
    }

    @Inject
    public MyService(ObjectDatastore datastore,
            MyDao myDao) {
    }

So the OD in the Dao is associated to the Thread that creates the servlet. When the servlet is called using the doPost, a method from the service is called. So I guess it is a different thread and the service uses a OD created in another thread. I guess this is the problem. I am using the OD as NO_SCOPE.

Do you have an idea on how to solve the problem?
Thanks

John Patterson

unread,
Jun 24, 2011, 11:58:00 PM6/24/11
to twig-p...@googlegroups.com
On 25/06/2011 10:48, Sydney wrote:
>
> Do you have an idea on how to solve the problem?
> Thanks
>

Yeah that will be it. Inject Provider<MyService> instead

Lucky for that new same-thread test!

Sydney

unread,
Jun 25, 2011, 12:04:38 AM6/25/11
to twig-p...@googlegroups.com
It works
Thanks :)
Reply all
Reply to author
Forward
0 new messages