Play Framework 2.2 Ebean dependencies? - maven

I'm in the process of migrating from Play Framework 2.1.5 to 2.2.6. I was having tons of errors like this:
[error] C:\dev\CS\trunk\app\models\Asset.java:57: error: cannot find symbol
[error] #NotNull
[error] ^
[error] symbol: class NotNull
[error] location: class Asset
and this:
play.PlayExceptions$CompilationException: Compilation error[error: package com.avaje.ebean.validation does not exist]
at play.PlayReloader$$anon$1$$anonfun$reload$2$$anonfun$apply$14$$anonfun$apply$16.apply(PlayReloader.scala:304) ~[na:na]
at play.PlayReloader$$anon$1$$anonfun$reload$2$$anonfun$apply$14$$anonfun$apply$16.apply(PlayReloader.scala:304) ~[na:na]
at scala.Option.map(Option.scala:145) ~[scala-library.jar:na]
at play.PlayReloader$$anon$1$$anonfun$reload$2$$anonfun$apply$14.apply(PlayReloader.scala:304) ~[na:na]
at play.PlayReloader$$anon$1$$anonfun$reload$2$$anonfun$apply$14.apply(PlayReloader.scala:298) ~[na:na]
I have found online in this thread that I needed to add a line in my dependencies to make it work.
"org.avaje.ebeanorm" % "avaje-ebeanorm-api" % "3.1.1",
I have multiple question about this:
1. Why is another import needed for Ebean? I have imported the javaEbean, shouldn't it be enough to be up and running? It was ok 2.1.5 and nothing point to that in the migration documentation.
2. When I look at this package, it seems to be used by nobody. Should I be using something else? Is this some kind of deprecated package?
3. The main reason I ask all of these questions is because, even if it work to resolve these dependencies on my dev machine (windows), when deploying on the server (unix), it doesn't download the same "sub-dependencies" and it doesn't work at runtime. All of the log point to this library causing trouble...
Thanks!

I have found my answer but it was a long journey, let's begin:
First, Ebean is a complete other project than Play Framework and between Play Framework 2.1 and Play Framework 2.2, the version from Ebean changed from 3.1.2 to 3.2.2. I could not found any release note or documentation but I have found a post from the author in a google group discussion that stated clearly that he deleted the validation from the Ebean library because people should use JSR 303 bean validation instead. Since Ebean is a one man show, the decision seems final.
The problem with that is that the library that provide this said bean validation (javax for example) are not called when doing an update() or a save() which is a regression in our code.
After numerous reading and testing, we have finally created a BaseModel based on Model that override the save() and update() method by calling a validator manully, like this:
#MappedSuperclass
public class BaseModel extends Model {
#Override
public void save() {
Set<ConstraintViolation<BaseModel>> constraints = validate();
if (constraints.size() > 0 ) {
onFoundConstraints(constraints);
} else {
super.save();
}
}
#Override
public void update() {
Set<ConstraintViolation<BaseModel>> constraints = validate();
if (constraints.size() > 0 ) {
onFoundConstraints(constraints);
} else {
super.update();
}
}
private Set<ConstraintViolation<BaseModel>> validate() {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
return validator.validate(this);
}
private void onFoundConstraints(Set<ConstraintViolation<BaseModel>> constraints) {
String allErrors = "";
for (ConstraintViolation<BaseModel> constraint : constraints) {
allErrors += constraint.getRootBeanClass().getSimpleName()+
"." + constraint.getPropertyPath() + " " + constraint.getMessage();
}
throw new RuntimeException(allErrors);
}
}
All our object now extends this class and it work well so far. I don't know if the previous validation was doing anything more than that but for our needs, it is ok.
I hope it help others since the Play Framework migration documentation doesn't even talk about this...

Related

Spring - generic superclass not instantiated properly?

ATM I am in the middle of refactoring our Selenium E2E Test Framework to use Spring.
My class/bean:
package info.fingo.selenium.utils.driver;
#Component
#Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public class ProxyDecorator extends WebDriverDecorator<WebDriver> {
#Autowired
public ProxyDecorator(TestUtils testUtils, DriverManager driverManager) {
super(WebDriver.class);
this.testUtils = testUtils;
this.driverManager = driverManager;
Superclass:
package org.openqa.selenium.support.decorators;
public class WebDriverDecorator<T extends WebDriver> {
private final Class<T> targetWebDriverClass;
private Decorated<T> decorated;
#SuppressWarnings("unchecked")
public WebDriverDecorator() {
this((Class<T>) WebDriver.class);
}
public WebDriverDecorator(Class<T> targetClass) {
this.targetWebDriverClass = targetClass;
}
public final T decorate(T original) {
Require.nonNull("WebDriver", original);
decorated = createDecorated(original);
return createProxy(decorated, targetWebDriverClass);
}
Issue occures on calling this line:
createProxy(decorated, targetWebDriverClass)
Where targetWebDriverClass for unknown reason is null and NullPointerException is later thrown.
This should not EVER happen as targetWebDriverClass is ALWAYS set through constructor - either provided by client (calling super(class)) or defaulted to WebDriver.class in default WebDriverDecorator constructor. Worked fine without Spring, and unfortunately I don't understand Spring enough to get any information through debugging.
My Spring dependencies:
ext.springVersion = '2.7.1'
dependencies {
//SPRING BOOT
api "org.springframework.boot:spring-boot-starter:$springVersion",
"org.springframework.boot:spring-boot-starter-aop:$springVersion",
"org.springframework.boot:spring-boot-starter-test:$springVersion",
decorate method in superclass WebDriverDecorator in marked as final which makes it ineligible for Spring CGLIB proxying as it cannot proxy final methods (& classes) - Sorry, I don't know exact reason why this caused my issue.
This is not my own class, it is taken from inside of dependency so I cannot change this.
This means that this class cannot be managed by Spring. In order for this to somehow work I get rid of inheritance (extends keyword) and replace it with composition. Got to do some reflection magic (for one of its protected method) but this seems to do the trick.

Quarkus extension using a repository based on PanacheMongoRepository

I'm currently working on a Quarkus extension which is basically a filter that is using a PanacheMongoRepository. Here is a code snippet (this is in the runtime part of the extension) :
#Provider
#Priority(Priorities.AUTHORIZATION)
#AuthorizationSecured
public class AuthorizationFilter implements ContainerRequestFilter {
// Some injection here
#Inject
UserRepository userRepository;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
// Some business logic here...
UserEntity userEntity = userRepository.findByName(name);
// Some business logic here...
}
}
The repository :
#ApplicationScoped
public class UserRepository implements PanacheMongoRepository<UserEntity> {
public UserEntity findByName(String name) {
return find("some query...", name).firstResult();
}
}
When the repository is called, I get the following exception:
org.jboss.resteasy.spi.UnhandledException: java.lang.IllegalStateException: This method is normally automatically overridden in subclasses...
java.lang.IllegalStateException: This method is normally automatically overridden in subclasses\n\tat io.quarkus.mongodb.panache.common.runtime.MongoOperations.implementationInjectionMissing(MongoOperations.java:765)\n\tat io.quarkus.mongodb.panache.PanacheMongoRepositoryBase.find(PanacheMongoRepositoryBase.java:119)
The processor
class AuthorizeProcessor {
private static final String FEATURE = "authorize";
#BuildStep
FeatureBuildItem feature() {
return new FeatureBuildItem(FEATURE);
}
#BuildStep(onlyIf = IsAuthorizeEnabled.class)
void registerAuthorizeFilter(
BuildProducer<AdditionalBeanBuildItem> additionalBeanProducer,
BuildProducer<ResteasyJaxrsProviderBuildItem> resteasyJaxrsProviderProducer
) {
additionalBeanProducer.produce(new AdditionalBeanBuildItem(UserRepository.class));
additionalBeanProducer.produce(new AdditionalBeanBuildItem(AuthorizationFilter.class));
resteasyJaxrsProviderProducer.produce(new ResteasyJaxrsProviderBuildItem(AuthorizationFilter.class.getName()));
}
}
Any idea ?
Thanks for your help :)
MongoDB with Panache (and the same for Hibernate with Panache) uses bytecode enhancement at build time. When this enhancement didn't occurs it leads to the exception you mentionned at runtime: java.lang.IllegalStateException: This method is normally automatically overridden in subclasses
It can occurs only when the repository or entity is not in the Jandex index. Jandex is used to index all the code of your application to avoid using reflection and classpath scanning to discover classes. If your entity / repository is not in the index this means it's not part of your application as we automatically index the classes of your application, so it must be inside an external JAR.
Usually, this is solved by adding the Jandex plugin to index the code of the external JAR (in fact there is multiple way to do this, see How to Generate a Jandex Index).
An extension suffer from the same issue as extensions are not indexed by default. But from an extension you can index the needed classes via a build step wich is more easy and avoid polluting the index with classes that are not needed.
This can be done by generating a new AdditionalIndexedClassesBuildItem(UserRepository.class.getName()) inside a build step.

SpringBoot log4j AppenderSkeleton The method append(LoggingEvent) must override or implement a supertype method

I'm trying to create a custom appender using log4j after looking at the given example -
Link:- How to create my own Appender in log4j?
I did as follows:-
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.spi.LoggingEvent;
public class MyCustomAppender extends AppenderSkeleton
{
private MailServiceImpl mail = new MailServiceImpl();
#Override
public void close() {
}
#Override
public boolean requiresLayout() {
return false;
}
#Override
protected void append(LoggingEvent event) {
mail.sendMail(event.toString());
}
}
It gives me error because of the overridden methods - The method append(LoggingEvent) of type MyCustomAppender must override or implement a supertype method. I tried to search for solution but found none. And nobody seem to have faced the problem. Where am I going wrong? Please help me.
I believe you are looking for a solution for Log4j2 but the stackoverflow page you are linking to is over 3 years old ( might be an older version of Log4j )
Looking at javadoc of older version it does show AppenderSkeleton could be used to override the appender() method however you mention you get a compile error
The method append(LoggingEvent) of type MyCustomAppender must override
or implement a supertype method
This is because there is no such method to override in Log4j2
Please provide version of what Log4j you are using, meanwhile have a look at this answer incase you are using Log4j2

MVC6 Access DbContext From Classes Not Related To Controller

I am developing a ASP.Net5 MVC6 website Using EF7.
I wanted to access DbContext from one of my classes which is not being called from Controller.
Is it possible to access from there? If yes then please guide me a little so that I can learn how to do it.
So far searched a lot from GitHub and stackoverflow. Very little information on this topic.
If i need to inject to my class then how should I do it?
public class CarAppContext : DbContext
{
public DbSet<Car> Cars { get; set; }
public DbSet<BodyType> BodyTypes { get; set; }
}
public Class NotificationManager
{
CarAppContext ctx;
public NotificationManager(CarAppContext AppCtx)
{
ctx = AppCtx;
}
public void SendNotification(Car HisCar, UserNotification HisNotification)
{
//need to check he has subscribed or not
//ctx is null here
}
}
You could call new CarAppContext().
But if you want to use Dependency Injection instead, you will need to make sure that
You have registered both CarAppContext and NotificationManager with the dependency injection container (generally done in Startup.Configure)
Instantiate NotificationManager from dependency injection
Not surprised you haven't found docs. As ASP.NET 5 is still in beta, our docs haven't been written yet. When its ready, there will be more posted here: http://docs.asp.net/en/latest/fundamentals/dependency-injection.html
Dependency injection is "viral" concept and you have to use it overall in application - pass dependencies via parameters/properties and have single (or few of) registration root. So the answer is - register NotificationManager as dependency.
Even Microsoft's implementation of dependency injection is abstracted enough, so you could easy have kind of classes for each component registers dependencies (like Ninject modules).
Note: Make sure to add this to your file...
using Microsoft.Data.Entity;

Is there a better way to use Structuremap to inject dependencies into a custom RoleProvider?

I found http://www.devproconnections.com/content1/catpath/database-development/topic/a-perfect-storm-linq-to-sql-dependency-injection-and-asp-net-providers/page/2 and had similar code as from the webpage:
public class CustomProvider : MembershipProvider, IMembershipProvider
{
private IUserRepository _userRepo;
// this .ctor is used via unit tests (as a seam)
public CustomProvider(IUserRepository repo)
{
this._userRepo = repo;
}
// requisite parameter-less constructor:
public CustomProvider()
{
// do NOTHING here
}
public override bool ValidateUser(string username, string password)
{
// HACK:
IUserRepository repo = this._userRepo ?? ObjectFactory.GetInstance<IUserRepository>();
SiteUser user = repo.GetUserByEmailAddress(username.ToLower());
if (user == null)
return false;
if (!user.Active || !user.Verified)
return false;
if (user.PassPhrase.IsNullOrEmpty())
return false;
// do other verification... etc
}
}
Except mine is a custom RoleProvider. Is calling the ObjectFactory.GetInstance an accepted way to inject dependencies into a RoleProvider? I tried to setup a property to inject the dependency, but I could not get that to work. I'm sure my StructureMap registry is wrong. But hard to find out the right way when the documentation is out of date.
So for an ASP.NET MVC3 app, is calling the ObjectFactory ok in a custom RoleProvider? Or should I attempt to inject to a property?
If a property, how? I have For<RoleProvider>().Use(ctx => Roles.Provider); currently. But I'm not sure id the Use should be an Add, nor am I sure on the syntax to inject a dependency into a property.
Still Need help
I'm having an awful time trying to make miniprofiler not throw Null ref exceptions when I merely move the StructureMap ObjectFactory to a property for init. The goal is to allow roles to be cached. I get the same error as these questions mini-profiler nullreferenceexception Help Configure mvc mini profiler with Linq to Sql
I've updated to the latest MVCMiniProfiler and tried it's MVC package. Seems that profiling isn't enabled before the custom RoleProvider is init or the properties are initialized. If I set the field straight from the overridden GetRolesForUser method, everything is fine. If I make that field a backer to a public property, I get NULL exceptions in ProfiledDbCommand. Why?
The Microsoft "provider" pattern does not work well with dependency injection, because of its reliance on statics and singletons. If you have to use a Provider, just do the service location via ObjectFactory.GetInstance and move on.

Resources