yahoo / elide

Elide is a Java library that lets you stand up a GraphQL/JSON-API web service with minimal effort.
https://elide.io
Other
1k stars 228 forks source link

JEE integration #652

Open belovaf opened 6 years ago

belovaf commented 6 years ago

Hello! We deploy Elide on JEE container and we have 2 problems: JsonApiEndpoint class has no default constructor, so it can't be instantiated by container with auto scanning. We should register @Application class and create JsonApiEndpoint manually. Similar story is with Elide class.

We use "bridge" producers to integrate with Elide (CDI @Produces), but it can be simplier if 1) JsonApiEndpoint will use field injection 2) Elide class will implement some interface

DennisMcWherter commented 6 years ago

I have been thinking about point 1. I wonder if it would be better to provide a separate instance of JsonApiEndpoint that provides a trivial constructor and field injection; it would just wrap the existing JsonApiEndpoint. In the context where a JEE container isn't being used (or any injection for that matter), it may be unnatural to rely on field injection for constructing the class.

As to the second point, can you please elaborate on how you're trying to instantiate Elide? Typically, we envisioned this would be built using the builder, bound to the injection framework (or passed into a manually created endpoint), and never manipulated directly beyond that. In this case, I don't see why you would want to instantiate it differently. However, we could certainly be making a poor assumption about this! 😄

belovaf commented 6 years ago

My main problem is that I can't declare Elide or JsonApiEndpoint as EJB or CDI bean. It's not possible to do this without copy-pasting JsonApiEndpoint and creating wrapper for Elide. If you just extract interface from Elide it will be much easier.

I use producer-methods to instantiate Elide:

@ApplicationScoped
public class ElideProducer {
    @Inject
    private DataStore store;

    @Produces
    @Singleton
    public Elide getElide() {
        EntityDictionary dictionary = new EntityDictionary(Collections.emptyMap());
        ElideSettings elideSettings = new ElideSettingsBuilder(store)
                .withUseFilterExpressions(true)
                .withEntityDictionary(dictionary)
                .withJoinFilterDialect(new RSQLFilterDialect(dictionary))
                .withSubqueryFilterDialect(new RSQLFilterDialect(dictionary))
                .build();
        return new Elide(elideSettings);
    }
}

With this configuration all DataStores should implement all transaction logic by themselves. I can't add @Transactional on Elide singleton.

I think the most flexible and simple way to implement transactions is to create DataStores which don't care about transactions at all. Then just add @Transactional or @TransactionAttribute on Elide class. Now Transaction interface has 2 responsibilities: manage transactions, define Repository methods.

Most environments already implement correct transaction management, I want be able to use these implementations and not reinvent the wheel.

P.S. Sorry for my awful English! 😄