Timmey92
Commodore
- Registriert
- Okt. 2008
- Beiträge
- 4.567
Moin,
ich arbeite mich im Moment in AngularJS auf Frontend und Play Framework (Java) auf Serverseite ein. Als DI Framework kommt Spring zum Einsatz. Auf das Problem bin ich gestoßen, als ich in einer Authentifizierungsklasse das UserRepository injizieren wollte. NullPointerException, geht also nicht.
Versionen: (build.sbt)
Play Framework 2.3.8
Um das ganze lauffähig zu bekommen habe ich in der Global.java (nach dem Tutorial auf der Play Seite) folgendermaßen:
In den Controllern funktioniert die Injizierung ganz gut (Konstruktorbasierte Injizierung):
In diesem Code kommt das Problem, Zeile 22. Über den Konstruktor kann ich das nicht injizieren, weil das Play Framework dann irgendwie einen Default Konstruktor vermisst (der wird erst zur Laufzeit erstellt).
Ideen was ich falsch mache, bzw. wie ich dort mein JPA Repository injiziert bekomme?
ich arbeite mich im Moment in AngularJS auf Frontend und Play Framework (Java) auf Serverseite ein. Als DI Framework kommt Spring zum Einsatz. Auf das Problem bin ich gestoßen, als ich in einer Authentifizierungsklasse das UserRepository injizieren wollte. NullPointerException, geht also nicht.
Versionen: (build.sbt)
Play Framework 2.3.8
Code:
libraryDependencies ++= Seq(
javaCore,
javaJpa,
javaJpa.exclude("org.hibernate.javax.persistence", "hibernate-jpa-2.0-api"),
"org.hibernate" % "hibernate-entitymanager" % "4.3.9.Final",
"org.springframework" % "spring-context" % "4.1.6.RELEASE",
"javax.inject" % "javax.inject" % "1",
"org.springframework.data" % "spring-data-jpa" % "1.8.0.RELEASE",
"org.postgresql" % "postgresql" % "9.4-1201-jdbc41",
"org.mockito" % "mockito-core" % "1.9.5" % "test"
)
Um das ganze lauffähig zu bekommen habe ich in der Global.java (nach dem Tutorial auf der Play Seite) folgendermaßen:
Code:
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.hibernate3.HibernateExceptionTranslator;
import org.springframework.orm.jpa.JpaTransactionManager;
import play.Application;
import play.GlobalSettings;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
/**
* Application wide behaviour. We establish a Spring application context for the dependency injection system and
* configure Spring Data.
*/
public class Global extends GlobalSettings {
/**
* The name of the persistence unit we will be using.
*/
static final String DEFAULT_PERSISTENCE_UNIT = "default";
/**
* Declare the application context to be used - a Java annotation based application context requiring no XML.
*/
final private AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
/**
* Sync the context lifecycle with Play's.
*/
@Override
public void onStart(final Application app) {
super.onStart(app);
System.out.println("Loading spring configuration");
// AnnotationConfigApplicationContext can only be refreshed once, but we do it here even though this method
// can be called multiple times. The reason for doing during startup is so that the Play configuration is
// entirely available to this application context.
ctx.register(SpringDataJpaConfiguration.class);
ctx.scan("controllers", "models");
ctx.refresh();
// This will construct the beans and call any construction lifecycle methods e.g. @PostConstruct
ctx.start();
// load the demo data in dev mode
/*if (Play.isDev() && !userRepository.findAll().iterator().hasNext()) {
DemoData.loadDemoData(userRepository);
}*/
}
/**
* Sync the context lifecycle with Play's.
*/
@Override
public void onStop(final Application app) {
// This will call any destruction lifecycle methods and then release the beans e.g. @PreDestroy
ctx.close();
super.onStop(app);
}
/**
* Controllers must be resolved through the application context. There is a special method of GlobalSettings
* that we can override to resolve a given controller. This resolution is required by the Play router.
*/
@Override
public <A> A getControllerInstance(Class<A> aClass) {
return ctx.getBean(aClass);
}
/**
* This configuration establishes Spring Data concerns including those of JPA.
*/
@Configuration
@EnableJpaRepositories("models")
public static class SpringDataJpaConfiguration {
@Bean
public EntityManagerFactory entityManagerFactory() {
return Persistence.createEntityManagerFactory(DEFAULT_PERSISTENCE_UNIT);
}
@Bean
public HibernateExceptionTranslator hibernateExceptionTranslator() {
return new HibernateExceptionTranslator();
}
@Bean
public JpaTransactionManager transactionManager() {
return new JpaTransactionManager();
}
}
}
In den Controllern funktioniert die Injizierung ganz gut (Konstruktorbasierte Injizierung):
Code:
@Named
@Singleton
@Security.Authenticated(SecuredApi.class)
public class WorkoutREST extends Controller {
private final WorkoutRepository workoutRepository;
@Inject
public WorkoutREST(final WorkoutRepository workoutRepository) {
this.workoutRepository = workoutRepository;
}
public Result getAll() {
List<Workout> workout = (List<Workout>) workoutRepository.findAll();
return ok(toJson(workout));
}
public Result get(long id) {
Workout workout = workoutRepository.findOne(id);
return ok(toJson(workout));
}
public Result add() {
Http.RequestBody body = request().body();
Workout workout = Workout.fromJson(body.asJson());
workoutRepository.save(workout);
return ok("Got json: " + body.asJson());
}
public Result update(Long id) {
Workout workout = fromJson(request().body().asJson(), Workout.class);
workoutRepository.save(workout);
return ok(toJson(workout));
}
In diesem Code kommt das Problem, Zeile 22. Über den Konstruktor kann ich das nicht injizieren, weil das Play Framework dann irgendwie einen Default Konstruktor vermisst (der wird erst zur Laufzeit erstellt).
Code:
package controllers.security;
import models.User;
import org.springframework.beans.factory.annotation.Autowired;
import play.mvc.Http.Context;
import play.mvc.Result;
import play.mvc.Security;
import models.UserRepository;
import javax.inject.Inject;
public class SecuredApi extends Security.Authenticator {
private UserRepository userRepository;
@Override
public String getUsername(Context ctx) {
User user = null;
String[] authTokenHeaderValues = ctx.request().headers().get(SecurityController.AUTH_TOKEN_HEADER);
if ((authTokenHeaderValues != null) && (authTokenHeaderValues.length == 1) && (authTokenHeaderValues[0] != null)) {
System.out.println("Auth Token Content: "+ authTokenHeaderValues[0]);
user = userRepository.findByAuthToken(authTokenHeaderValues[0]);
if (user != null) {
ctx.args.put("user", user);
return user.getEmailAddress();
}
}
return null;
}
@Inject
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public Result onUnauthorized(Context ctx) {
return unauthorized();
}
}
Ideen was ich falsch mache, bzw. wie ich dort mein JPA Repository injiziert bekomme?
Zuletzt bearbeitet: