Play 2.6 pass new/blank/empty Form<LoginForm> from controller to login.scala.html


(Mule52) #1

I have upgraded to play 2.6 from 2.5. I am following examples I find online, but I stuck with this issue. I am creating a simple login.scala.html and I want to use the @helper.form, @helper.inputText, and @helper.inputPassword. I need to pass in an empty/blank Form[LoginForm] object from my Java controller to my twirl template, but it is failing. My code is below.

Below is my simple LoginForm class, then my login.scala.html, and finally my Application Java controller. I am stuck on compilation errors, see Application - login() for comments.

Thanks for any suggestions.

package models;

public class LoginForm {
    public String email;
    public String password;
    public boolean rememberMe;

    public LoginForm(String email, String password) {
        this.email = email;
        this.password = password;
    }
}
@this(main: views.html.main)
@(form: Form[LoginForm])

@main("Login", "login") {

    <div>
        <h1>User Login</h1>

        @helper.form(routes.Application.doLogin()) {

            @helper.CSRF.formField

            @helper.inputText(
                form("username"),
                '_label -> "Username",
                'placeholder -> "username",
                'id -> "username",
                'size -> 60
            )

            @helper.inputPassword(
                form("password"),
                '_label -> "Password",
                'placeholder -> "password",
                'id -> "password",
                'size -> 60
            )

            <button type="submit">Login</button>
        }
    </div>
}
package controllers;

import models.LoginForm;
import com.google.inject.Inject;
import play.data.Form;
import play.data.FormFactory;
import play.mvc.*;

public class Application extends Controller {

    @Inject views.html.index indexTemplate;
    @Inject views.html.players playersTemplate;
    @Inject views.html.lists listsTemplate;
    @Inject views.html.tags tagsTemplate;
    @Inject views.html.users usersTemplate;
    @Inject views.html.boards dashboardsTemplate;
    @Inject views.html.activity activityTemplate;
//    @Inject views.html.login loginTemplate;

    private final FormFactory formFactory;

    @Inject
    public Application(FormFactory formFactory) {
        this.formFactory = formFactory;
    }

    public Result index() {
        return ok(indexTemplate.render());
    }

    public Result login() {
        // Do I need to pass an empty Form<LoginForm> into the render?
        LoginForm loginForm = new LoginForm("me@test.com", "mypassword");

        Form<LoginForm> form = formFactory.form(LoginForm.class);
        Form<LoginForm> filledForm = form.fill(loginForm);

        // While I can pass in objects like Strings to this render method and they work,
        // when I pass in my filledForm object, I get fatal errors.
//        return ok(loginTemplate.render(filledForm));

		// This is a 2.5 approach that I am used to using, but I get the following compilation error.
		// Non-static method 'render(models.LoginForm)' cannot be references from a static context.		
        return ok(views.html.login.render(filledForm));
    }

    public Result doLogin() {
    	// I have not reached this step yet.
        Form<LoginForm> loginForm = formFactory.form(LoginForm.class).bindFromRequest();
        return ok(indexTemplate.render());
    }
}

(Greg Methvin) #2

Your template is no longer a static template, since you’ve added:

@this(main: views.html.main)

When you do this, Twirl will generate a constructor for your template, and the render method will be an instance method rather than a static method.

If you remove the @this line it should work exactly as in 2.5, or you can inject an instance and call render on that.

You mentioned you get fatal errors when you try to pass your form to the injected template. What do the errors look like? I did notice your template references the “username” field of the form, but your login form does not have a field named username.


(Mule52) #3

I appreciate your response.

If I do this below, I get the fatal error during run time. It looks like the @helper.inputText(form(“email”)) is not working like examples I see online. I am following this example (UserForm towards the bottom), https://www.playframework.com/documentation/2.6.x/JavaFormHelpers.

@this(main: views.html.main)
@(form: Form[LoginForm])

@main("Login", "login") {

    @helper.inputText(
                form("email")
            )
}

With my controller below…

package controllers;

import models.LoginForm;
import com.google.inject.Inject;
import play.data.Form;
import play.data.FormFactory;
import play.mvc.*;

public class Application extends Controller {

    @Inject views.html.index indexTemplate;
    @Inject views.html.login loginTemplate;

    private final FormFactory formFactory;

    @Inject
    public Application(FormFactory formFactory) {
        this.formFactory = formFactory;
    }

    public Result login() {
        LoginForm loginForm = new LoginForm("me@test.com", "mypassword");
        Form<LoginForm> form = formFactory.form(LoginForm.class);
        Form<LoginForm> filledForm = form.fill(loginForm);
        return ok(loginTemplate.render(filledForm));
    }
}

I am able to pass the filled form, but just not use the helper example at this point. Thanks for any suggestions.

The error I am getting when I reference @helper.inputText(form(“name”)) in my login.scala.html… I’ve tried “name, email, Name,” … many combinations.

Uncaught error from thread [application-akka.actor.default-dispatcher-4]: org/springframework/core/ErrorCoded, shutting down JVM since ‘akka.jvm-exit-on-fatal-error’ is enabled for for ActorSystem[application]
java.lang.NoClassDefFoundError: org/springframework/core/ErrorCoded
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at play.data.Form.field(Form.java:953)
at play.data.Form.apply(Form.java:936)
at views.html.login.apply(login.template.scala:42)
at views.html.login.render(login.template.scala:51)
at controllers.Application.login(Application.java:71)
at router.Routes$$anonfun$routes$1.$anonfun$applyOrElse$16(Routes.scala:334)
at play.core.routing.HandlerInvokerFactory$$anon$3.resultCall(HandlerInvoker.scala:134)
at play.core.routing.HandlerInvokerFactory$$anon$3.resultCall(HandlerInvoker.scala:133)
at play.core.routing.HandlerInvokerFactory$JavaActionInvokerFactory$$anon$8$$anon$2$$anon$1.invocation(HandlerInvoker.scala:108)
at play.core.j.JavaAction$$anon$1.call(JavaAction.scala:82)
at play.http.DefaultActionCreator$1.call(DefaultActionCreator.java:31)
at play.core.j.JavaAction.$anonfun$apply$8(JavaAction.scala:132)
at scala.concurrent.Future$.$anonfun$apply$1(Future.scala:655)
at scala.util.Success.$anonfun$map$1(Try.scala:251)
at scala.util.Success.map(Try.scala:209)
at scala.concurrent.Future.$anonfun$map$1(Future.scala:289)
at scala.concurrent.impl.Promise.liftedTree1$1(Promise.scala:29)
at scala.concurrent.impl.Promise.$anonfun$transform$1(Promise.scala:29)
at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:60)
at play.core.j.HttpExecutionContext$$anon$2.run(HttpExecutionContext.scala:56)
at play.api.libs.streams.Execution$trampoline$.execute(Execution.scala:70)
at play.core.j.HttpExecutionContext.execute(HttpExecutionContext.scala:48)
at scala.concurrent.impl.CallbackRunnable.executeWithValue(Promise.scala:68)
at scala.concurrent.impl.Promise$KeptPromise$Kept.onComplete(Promise.scala:368)
at scala.concurrent.impl.Promise$KeptPromise$Kept.onComplete$(Promise.scala:367)
at scala.concurrent.impl.Promise$KeptPromise$Successful.onComplete(Promise.scala:375)
at scala.concurrent.impl.Promise.transform(Promise.scala:29)
at scala.concurrent.impl.Promise.transform$(Promise.scala:27)
at scala.concurrent.impl.Promise$KeptPromise$Successful.transform(Promise.scala:375)
at scala.concurrent.Future.map(Future.scala:289)
at scala.concurrent.Future.map$(Future.scala:289)
at scala.concurrent.impl.Promise$KeptPromise$Successful.map(Promise.scala:375)
at scala.concurrent.Future$.apply(Future.scala:655)
at play.core.j.JavaAction.apply(JavaAction.scala:132)
at play.api.mvc.Action.$anonfun$apply$2(Action.scala:96)
at play.api.libs.streams.StrictAccumulator.$anonfun$mapFuture$4(Accumulator.scala:174)
at scala.util.Try$.apply(Try.scala:209)
at play.api.libs.streams.StrictAccumulator.$anonfun$mapFuture$3(Accumulator.scala:174)
at scala.Function1.$anonfun$andThen$1(Function1.scala:52)
at scala.Function1.$anonfun$andThen$1(Function1.scala:52)
at play.api.libs.streams.StrictAccumulator.run(Accumulator.scala:207)
at play.core.server.AkkaHttpServer.$anonfun$runAction$4(AkkaHttpServer.scala:305)
at akka.http.scaladsl.util.FastFuture$.strictTransform$1(FastFuture.scala:41)
at akka.http.scaladsl.util.FastFuture$.$anonfun$transformWith$3(FastFuture.scala:51)
at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:60)
at akka.dispatch.BatchingExecutor$AbstractBatch.processBatch(BatchingExecutor.scala:55)
at akka.dispatch.BatchingExecutor$BlockableBatch.$anonfun$run$1(BatchingExecutor.scala:91)
at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
at scala.concurrent.BlockContext$.withBlockContext(BlockContext.scala:81)
at akka.dispatch.BatchingExecutor$BlockableBatch.run(BatchingExecutor.scala:91)
at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:40)
at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(ForkJoinExecutorConfigurator.scala:43)
at akka.dispatch.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at akka.dispatch.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
at akka.dispatch.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
at akka.dispatch.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
Caused by: java.lang.ClassNotFoundException: org.springframework.core.ErrorCoded
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
… 89 more
[error] a.a.ActorSystemImpl - Uncaught error from thread [application-akka.actor.default-dispatcher-4]: org/springframework/core/ErrorCoded, shutting down JVM since ‘akka.jvm-exit-on-fatal-error’ is enabled for ActorSystem[application]
java.lang.NoClassDefFoundError: org/springframework/core/ErrorCoded
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
Caused by: java.lang.ClassNotFoundException: org.springframework.core.ErrorCoded
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
Disconnected from the target VM, address: ‘127.0.0.1:34403’, transport: ‘socket’


(Greg Methvin) #4

NoClassDefFoundError is almost always caused by incompatible dependency versions. In this case your app is trying to load the class org.springframework.core.ErrorCoded. Play uses the Spring data binder internally for its Java forms implementation, so that’s probably why it’s trying to load that class. It looks like this class was removed in Spring 5.0.0, but Play 2.6 is still on 4.3.11. This could be because you have a dependency on Spring 5.x somewhere.

I would check what Spring dependencies you have. You can use https://github.com/jrudolph/sbt-dependency-graph to do that, using dependencyList to list dependencies and see if you notice any Spring 5.x dependencies. If you see a Spring 5.x dependency you can use whatDependsOn or dependencyTree to see which library is bringing it in.


(Mule52) #5

Again, thanks for the help.

I do have a dependency on Spring 5.0.0, and it is coming from Pac4J, which I have recently added to determine if I want to use this library for authentication. If I am to continue using this library, does that mean I cannot use the Play helpers for forms? If I comment out my Pac4J dependencies, the Play 2.6 Java form helpers work fine (https://www.playframework.com/documentation/2.6.x/JavaFormHelpers).

Here is the results of my dependencies.

[info] org.springframework:spring-core:5.0.2.RELEASE
[info] ±com.typesafe.play:play-java-forms_2.12:2.6.10 [S]
[info] | ±be.objectify:deadbolt-java_2.12:2.6.1 [S]
[info] | | ±com.mycompany:mycompany_2.12:1.0 [S]
[info] | |
[info] | ±com.mycompany:mycompany_2.12:1.0 [S]
[info] |
[info] ±org.pac4j:pac4j-kerberos:3.0.0
[info] | ±com.mycompany:mycompany_2.12:1.0 [S]
[info] |
[info] ±org.pac4j:pac4j-saml:3.0.0
[info] ±com.mycompany:mycompany_2.12:1.0 [S]
[info]

[myproject] $ whatDependsOn org.springframework spring-jcl 5.0.2.RELEASE
[info] org.springframework:spring-jcl:5.0.2.RELEASE
[info] ±org.springframework:spring-core:5.0.2.RELEASE
[info] ±com.typesafe.play:play-java-forms_2.12:2.6.10 [S]
[info] | ±be.objectify:deadbolt-java_2.12:2.6.1 [S]
[info] | | ±com.mycompany:mycompany_2.12:1.0 [S]
[info] | |
[info] | ±com.mycompany:mycompany_2.12:1.0 [S]
[info] |
[info] ±org.pac4j:pac4j-kerberos:3.0.0
[info] | ±com.mycompany:mycompany_2.12:1.0 [S]
[info] |
[info] ±org.pac4j:pac4j-saml:3.0.0
[info] ±com.mycompany:mycompany_2.12:1.0 [S]
[info]