mkurz/deadbolt-2-java

Deadbolt depends on global state :(

Closed this issue · 8 comments

mkurz commented

Hi Steve,

if you set play.allowGlobalApplication = false in your application.conf apps using deadbolt helpers will break.
You probably already know that.

That's because all your helpers import the current play application:
https://github.com/schaloner/deadbolt-2-java/blob/v2.5.5/code/app/be/objectify/deadbolt/java/views/restrict.scala.html#L5
which unfortunately is needed for the implicit import one line above - which then boils down to this here:
https://github.com/schaloner/deadbolt-2-java/blob/v2.5.5/code/app/be/objectify/deadbolt/java/ViewAccessPoint.scala#L31-L33

How can we get rid of the global app dependency in deadbolt?

I've been thinking about this, and I don't want to break backwards compatibility. I think the way forward is to extract anything linked to global state into a separate companion library and have purely DI components in the core. This means, off the top of my head, ViewAccessPoint and all templates. The new DI templates that will exist in the core will have a package shift to views.di.XXX to avoid conflicts.

Any thoughts on this approach?

mkurz commented

I think this is a very good approach. Actually I was thinking in the same direction during I put #38 together.

Hi,

I've pulled out the global state (mostly views) into this library: https://github.com/schaloner/deadbolt-2-java-global-state

The templates in this library are now in views.di. All tests, etc, updated but there's probably a bunch more stuff I need to do, like expose the templates via a module. I'll get on this and documentation tomorrow.

mkurz commented

This is really awesome, thanks! I will try and give you feedback as soon as possible (probably Monday)

I've also added you as a collaborator for the new repo

Hi,
I am currently migrating from Play 2.5 to 2.6 and have to upgrade Deadbolt too.
In my project I am using template constraints like @restrict and want to continue to use them. I have seen that you removed the way they worked before in favor of injected templates what I think is the right way to go. However I have no clue what I have to inject so I would appreciate it if you could give an example how to do that. Your manual is mentioning that I could still use the Global State by importing another dependency but I do not want to do that so my project is as future-proof as possible.

Hi,

to use dependency injection in templates, you have to have your templates injected into your controllers. For example, if you have a controller that uses a template called foo, under the 2.5 way of doing things, you would have something like

import com.example.views.html.foo;
public class Bar extends Controller {
    public Result somethingFoo() {
            return ok(foo.render())
    }
}

Under 2.6 with dependency injection, you just need to change this to

import com.example.views.html.foo;
public class Bar extends Controller {

    private final foo fooTemplate;
    
    @javax.inject.Inject
    public Bar(final foo fooTemplate) {
        this.fooTemplate = fooTemplate;
    }

    public Result somethingFoo() {
            return ok(fooTemplate.render())
    }
}

This means you're calling ´render´ on an instance of ´foo´.

Within the foo template, you also need to add what you essentially thing of as a constructor. So, instead of

@import be.objectify.deadbolt.java.views.html.subjectPresent
@subjectPresent() {
    something
} 

instead, you need to inject Deadbolt support like this

@this(subjectPresent: be.objectify.deadbolt.java.views.html.subjectPresent)
@subjectPresent() {
    something
} 

I dropped the import in the second example to make it clearer what you're importing.

I hope this helps, and if something still isn't clear then please let me know. This example will be going into the documentation, so thanks for triggering that.

Regards,
Steve

mkurz commented

@schaloner Thanks for this, the DI approach is working great for me!