When running 2.5.18 application using MessagesApi, I am receiving the error "Unexpected exception ExceptionInInitializerError: null"

java

(Dan Zeller) #1

I am attempting to move my application from 2.5.12 to 2.5.18, and then onto 2.6.x. I am using the MessagesApi since I read that the old Message is deprecated.

I have a controller, Application.java which I have set up the MessagesApi and Messages objects and receive no errors in compiling, but receive this error when attempting to run the application:

[error] application -

! @77h0ppgdc - Internal server error, for (GET) [/] ->

play.api.UnexpectedException: Unexpected exception[ExceptionInInitializerError: null]
        at play.core.server.DevServerStart$$anon$1.$anonfun$get$3(DevServerStart.scala:187)
        at scala.Option.map(Option.scala:146)
        at play.core.server.DevServerStart$$anon$1.$anonfun$get$2(DevServerStart.scala:133)
        at scala.util.Success.flatMap(Try.scala:247)
        at play.core.server.DevServerStart$$anon$1.$anonfun$get$1(DevServerStart.scala:131)
        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)
Caused by: java.lang.ExceptionInInitializerError: null
        at controllers.Application$$FastClassByGuice$$b5b6aa19.newInstance(<generated>)
        at com.google.inject.internal.DefaultConstructionProxyFactory$FastClassProxy.newInstance(DefaultConstructionProxyFactory.java:89)
        at com.google.inject.internal.ConstructorInjector.provision(ConstructorInjector.java:111)
        at com.google.inject.internal.ConstructorInjector.construct(ConstructorInjector.java:90)
        at com.google.inject.internal.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:268)
        at com.google.inject.internal.SingleParameterInjector.inject(SingleParameterInjector.java:38)
        at com.google.inject.internal.SingleParameterInjector.getAll(SingleParameterInjector.java:62)
        at com.google.inject.internal.ConstructorInjector.provision(ConstructorInjector.java:110)
        at com.google.inject.internal.ConstructorInjector.construct(ConstructorInjector.java:90)
        at com.google.inject.internal.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:268)
Caused by: java.lang.NullPointerException: null
        at controllers.Application.<clinit>(Application.java:75)
        at controllers.Application$$FastClassByGuice$$b5b6aa19.newInstance(<generated>)
        at com.google.inject.internal.DefaultConstructionProxyFactory$FastClassProxy.newInstance(DefaultConstructionProxyFactory.java:89)
        at com.google.inject.internal.ConstructorInjector.provision(ConstructorInjector.java:111)
        at com.google.inject.internal.ConstructorInjector.construct(ConstructorInjector.java:90)
        at com.google.inject.internal.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:268)
        at com.google.inject.internal.SingleParameterInjector.inject(SingleParameterInjector.java:38)
        at com.google.inject.internal.SingleParameterInjector.getAll(SingleParameterInjector.java:62)
        at com.google.inject.internal.ConstructorInjector.provision(ConstructorInjector.java:110)
        at com.google.inject.internal.ConstructorInjector.construct(ConstructorInjector.java:90)

The line that I am looking at:
at controllers.Application.<clinit>(Application.java:75)

Here is the snippet:

import play.i18n.Lang;
import play.i18n.Messages;
import play.i18n.MessagesApi;

public class Application extends Controller {
	
	@Inject
	MailerClient mailerClient;
	
	@Inject
	FormFactory formFactory;

    @Inject
    static MessagesApi messagesApi;
    
    static Collection<Lang> candidates = Collections.singletonList(new Lang(Locale.US));
    static Messages messages = messagesApi.preferred(candidates);
    ...
}

where in the Application.java controller is:
static Messages messages = messagesApi.preferred(candidates);

I built the code based on this document:
https://www.playframework.com/documentation/2.6.x/JavaI18N#Externalizing-messages

I am not sure how to tackle this one. I appreciate the help.


(Marcos Pereira) #2

Hi @Dan_Zeller,

What is happening here is that static fields are initialized before injecting the dependencies. This is not something related only to Play, but how objects are initialized in Java. Any reason to not have something like:

import play.i18n.Lang;
import play.i18n.Messages;
import play.i18n.MessagesApi;

public class Application extends Controller {

    private final MailerClient mailerClient;
    private final FormFactory formFactory;
    private final MessagesApi messagesApi;
    
    private final Collection<Lang> candidates;
    private final Messages messages;

    @Inject
    public Application(MailerClient mailerClient, FormFactory formFactory, MessagesApi messagesApi) {
        this.mailerClient = mailerClient;
        this.formFactory = formFactory;
        this.messagesApi = messagesApi;

        this.candidates = Collections.singletonList(new Lang(Locale.US));
        this.messages = messagesApi.preferred(candidates);
    }
}

Why are you making messagesApi, candidates and messages static? If you want to ensure these things aren’t happen more then once, it would be better to have Application annotated as a @Singleton.


(Greg Methvin) #3

Also, you’d traditionally want to get the candidate languages from the request, e.g. messagesApi.preferred(request()) in your controller method.


(Dan Zeller) #4

Thanks for the suggestion. As you mentioned, I updated my controller to:

public class Application extends Controller {

	private final MailerClient mailerClient;
	private final FormFactory formFactory;
	private final MessagesApi messagesApi;

	private final Collection<Lang> candidates;
	private final Messages messages;

	@Inject
	public Application(MailerClient mailerClient, FormFactory formFactory, MessagesApi messagesApi) {
		this.mailerClient = mailerClient;
		this.formFactory = formFactory;
		this.messagesApi = messagesApi;

		this.candidates = Collections.singletonList(new Lang(Locale.US));
		this.messages = messagesApi.preferred(candidates);
	}
        ...
}

and the application now runs.