Hi I would like to import Play framework Java Exension* into a Play framework Model.
In specific I'd like to have in my model:
package models;
// various import
import play.templates.JavaExtensions;
#Entity
public class Product extends Model {
#PrePersist
public void save_slug(){
slug = title.slugify();
}
}
But I'm receiving following error
The method slugify() is undefined for the type String
What am I doing wrong?
*references:
- http://www.playframework.org/documentation/1.1/javaextensions#aslugifya
- http://www.playframework.org/documentation/api/1.2.4/play%2Ftemplates%2FJavaExtensions.html
Java extensions are static methods of JavaExtensions class, you can use them as follows:
slug = JavaExtensions.slugify(title);
Related
Using Micronaut data v3, I created the following simple classes:
MyEntity.java
package test;
import io.micronaut.data.annotation.GeneratedValue;
import io.micronaut.data.annotation.Id;
import io.micronaut.data.annotation.MappedEntity;
#MappedEntity
public class MyEntity {
#id
#GeneratedValue(GeneratedValue.Type.AUTO)
Long id;
String name;
}
MyRepo.java:
package test;
import io.micronaut.data.jdbc.annotation.JdbcRepository;
import io.micronaut.data.model.query.builder.sql.Dialect;
import io.micronaut.data.repository.CrudRepository;
#JdbcRepository(dialect = Dialect.MYSQL)
public interface MyRepo extends CrudRepository<MyEntity, Long> {
}
The project can build without above 2 classes. Once I add these 2 classes, I got the error
java: Unable to implement Repository method: MyRepo.updateAll(Iterable arg0). No possible implementations found.
Given a Spring Data REST (SDR) server built with Spring Boot Gradle Plugin 2.2.5.RELEASE, is it possible to load an #Entity by self link within the server application?
I'm aware how to access it with an HTTP client, e.g. using curl:
$ curl localhost/users/1 # Responds with 200 OK and JSON representation
What I'm searching for is a mechanism to do this in the server using Java only, ideally using a standard SDR mechanism:
#Service
public class SelfLinkResolver {
public Object findBySelfLink(Link self) {
if (self == null || !self.getRel().equals(SELF)) {
throw new IllegalArgumentException("Non-null self link expected");
}
return null; // How to return the entity using a standard SDR mechanism?
}
public void exampleCall() {
Link self = new Link("localhost/users/1");
Object entity = findBySelfLink(self);
requireNonNull(entity, "Failed to load entity by self link");
}
}
An internal solution is parse your link and extract the ID (1 in your example), the call repository.findById(id).
Another solution would be new a RestTemplate, call your own API.
I finally came up with this solution, which uses SDR's UriToEntityConverter. In contrast to my question, it requires not only the self link, but also the entity class. It therefore doesn't fully answer my initial question.
I guess that there is no SDR solution that does not require the entity class, since there is no need for this within the framework, at least for usual API calls. SDR is always provided with the type information through the Repository, to which the self link refers. However, I didn't dive into other classes such as PersistentEntities, RepositoryInvokerFactory or Repositories, which might provide a solution for this.
WARNING: My tested implementation differs from this. This code is untested, but should illustrate the idea.
import lombok.NonNull;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.data.mapping.context.PersistentEntities;
import org.springframework.data.repository.support.Repositories;
import org.springframework.data.repository.support.RepositoryInvokerFactory;
import org.springframework.data.rest.core.UriToEntityConverter;
import org.springframework.hateoas.Link;
import org.springframework.stereotype.Component;
import java.net.URI;
import java.util.Optional;
import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.String.format;
import static org.springframework.hateoas.IanaLinkRelations.SELF;
#Component
public class SelfLinkToEntityConverter extends UriToEntityConverter {
private static final TypeDescriptor URI_DESCRIPTOR = TypeDescriptor.valueOf(URI.class);
SelfLinkToEntityConverter(#NonNull PersistentEntities entities,
#NonNull RepositoryInvokerFactory invokerFactory,
#NonNull Repositories repositories) {
super(entities, invokerFactory, repositories);
}
#NonNull
public <T> Optional<T> findBySelfLink(#NonNull Link self, #NonNull Class<T> entityClass) {
checkArgument(self.getRel().equals(SELF), "Non-null self link expected");
URI uri = self.expand().toUri();
TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(entityClass);
try {
#SuppressWarnings("unchecked")
T entity = (T) super.convert(uri, URI_DESCRIPTOR, typeDescriptor);
return Optional.ofNullable(entity);
} catch (IllegalArgumentException o_O) {
throw new IllegalArgumentException(format("Failed to load %s: %s",
entityClass.getSimpleName(), self.getHref()));
}
}
}
I just downloaded the play framework from their site and am working through this tutorial.
I've noticed the framework creates the folders app/controllers and app/views, but not a models folder. I created it manually and added Task.java to it. When I get to the section entitled "Rendering the first page" and open localhost:9000/tasks I get a compilation error that says package play.models does not exist. Here is what my Task.java looks like:
package models;
import java.util.*;
public class Task {
public Long id;
#Required
public String label;
public static List<Task> all() {
return new ArrayList<Task>();
}
public static void create(Task task) {
}
public static void delete(Long id) {
}
}
Here is application.java, the file generating the compilation error:
package controllers;
import play.*;
import play.mvc.*;
import views.html.*;
import play.data.*;
import play.models.*; // COMPILATION ERROR: "package play.models does not exist"!
public class Application extends Controller {
static Form<Task> taskForm = Form.form(Task.class);
public static Result index() {
//return ok(index.render("Your new application is ready."));
return redirect(routes.Application.tasks());
}
public static Result tasks() {
return ok(views.html.index.render(Task.all(), taskForm));
}
public static Result newTask() {
return TODO;
}
public static Result deleteTask(Long id) {
return TODO;
}
}
I believe it's supposed to be import models.Task; as opposed to import play.models.*;
That's quite confusing (IMHO) step in this tutorial, instead scroll down to Persist the tasks in a database section which describes preparing a model to cooperate with DB :) (it extends Model class, uses proper annotations, etc)
As you recognized it yet, you need to create a models package yourself.
Also as cYn wrote: you should import models like models.SomeModel into your controller
You are correct HukeLau_DABA , the Play will not create the models package for you. you have to create it.
I got these imports in my Application controller class. I got this sample play application running.
import play.api._
import play.api.mvc._
import play.api.data.Form
import play.api.data.Forms._
import models.Task
and another thing in Eclipse is it will not import the necessary imports automatically.
it is bit pain now, once the IDE support get better I hope this will change.
I found strange behaviour in my Play 1.2.x application
For example we has following code:
app/models/Account.java:
package models;
import javax.persistence.Entity;
import play.db.jpa.Model;
#Entity
public class Account extends Model {
public String username;
}
app/coutrollers/Application.java:
package controllers;
import play.mvc.Controller;
import java.util.List;
import models.Account;
public class Application extends Controller {
public static void index() {
Account account = Account.find("username LIKE ?", "username1").first();
account.username = "username3";
List<Account> accounts = Account.all().fetch();
render(account, accounts);
}
}
app/views/Application/index.html:
#{extends 'main.html' /}
#{set title:'Home' /}
<h2>Working!</h2>
${account.username}
<ul>
#{list items:accounts, as:'acc'}
<li>${acc.username}</li>
#{/list}
</ul>
With following accounts in database:
username1
username2
Output will be following:
Working!
username3
username3
username2
But must be as:
Working!
username3
username1
username2
What is this???
Play bug?
Java static context feature?
JPA feature?
...?
RESOLVED
Thanks for #millimoose. All that needs is a detach():
package controllers;
import play.mvc.Controller;
import java.util.List;
import models.Account;
import play.db.jpa.JPA;
public class Application extends Controller {
public static void index() {
Account account = Account.find("username LIKE ?", "username1").first();
account.username = "username3";
JPA.em().detach(account);
List<Account> accounts = Account.all().fetch();
render(account, accounts);
}
}
JPA works just like every other ORM on earth, in that when you look up the same database record twice, you will get the same object. The .first() query caches the Account internally (to track changes done to it done within a unit of work), and the .all().fetch() call just gives you that cached object again.
I'm not familiar with the Play! ORM stuff, but "raw" JPA has EntityManager.detach() to make it stop tracking a given entity instance. (And thus give you a new copy whenever the corresponding DB record is retrieved again.)
I am using Hibernate + JPA as my ORM solution.
I am using HSQL for unit testing and PostgreSQL as the real database.
I want to be able to use Postgres's native UUID type with Hibernate, and use the UUID in its String representation with HSQL for unit testing (since HSQL does not have a UUID type).
I am using a persistence XML with different configurations for Postgres and HSQL Unit Testing.
Here is how I have Hibernate "see" my custom UserType:
#Id
#Column(name="UUID", length=36)
#org.hibernate.annotations.Type(type="com.xxx.UUIDStringType")
public UUID getUUID() {
return uuid;
}
public void setUUID(UUID uuid) {
this.uuid = uuid;
}
and that works great. But what I need is the ability to swap out the "com.xxx.UUIDStringType" part of the annotation in XML or from a properties file that can be changed without re-compiling.
Any ideas?
Hy, for those who are seeking for a solution in Hibernate 4 (because the Dialect#addTypeOverride method is no more available), I've found one, underlying on this Steve Ebersole's comment
You have to build a custom user type like this one :
public class UUIDStringCustomType extends AbstractSingleColumnStandardBasicType {
public UUIDStringCustomType() {
super(VarcharTypeDescriptor.INSTANCE, UUIDTypeDescriptor.INSTANCE);
}
#Override
public String getName() {
return "pg-uuid";
}
}
And to bind it to the HSQLDB dialect, you must build a custom dialect that override the Dialect#contributeTypes method like this :
public class CustomHsqlDialect extends HSQLDialect {
#Override
public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
super.contributeTypes(typeContributions,serviceRegistry);
typeContributions.contributeType(new UUIDStringCustomType());
}
}
Then you can use the #Type(type="pg-uuid") with the two databases.
Hope it will help someone...
This question is really old and has been answered for a long time, but I recently found myself in this same situation and found a good solution. For starters, I discovered that Hibernate has three different built-in UUID type implementations:
binary-uuid : stores the UUID as binary
uuid-char : stores the UUID as a character sequence
pg-uuid : uses the native Postgres UUID type
These types are registered by default and can be specified for a given field with a #Type annotation, e.g.
#Column
#Type(type = "pg-uuid")
private UUID myUuidField;
There's also a mechanism for overriding default types in the Dialect. So if the final deployment is to talk to a Postgres database, but the unit tests use HSQL, you can override the pg-uuid type to read/write character data by writing a custom dialect like so:
public class CustomHSQLDialect extends HSQLDialect {
public CustomHSQLDialect() {
super();
// overrides the default implementation of "pg-uuid" to replace it
// with varchar-based storage.
addTypeOverride(new UUIDCharType() {
#Override
public String getName() {
return "pg-uuid";
}
});
}
}
Now just plug in the custom dialect, and the the pg-uuid type is available in both environments.
To avoid problems between the UUID types without specifying the #Type annotation (which basically means you have to adjust all annotations when you want to change from postgres to mysql or the other way around...) I'm using a package-info.java with the hibernates #TypeDef annotation on that package.
Here's an example setup of your application:
Assuming module/src/main/java/app.package.domain contains your entities. And you'r tests are stored in module/src/test/java/app.package.
Simply create two package-info.java in your domain packages.
Make sure the package-info files are always in the same package (for testing and production). See the following example below:
src/main/java
app
package
domain
package-info.java
src/test/java
app
package
domain
package-info.java
The content of you're production package-info.java should look like this (Postgres):
#TypeDef(
name = "pg-uuid",
defaultForType = UUID.class,
typeClass = PostgresUUIDType.class
)
package app.package.domain;
import org.hibernate.annotations.TypeDef;
import org.hibernate.type.PostgresUUIDType;
import java.util.UUID;
And this is how you'r testing "configuration" should look like (H2):
#TypeDef(
name = "uuid-char",
defaultForType = UUID.class,
typeClass = UUIDCharType.class
)
package app.package.domain;
import org.hibernate.annotations.TypeDef;
import org.hibernate.type.UUIDCharType;
import java.util.UUID;
Hope it helps
Perhaps you can build some smarts in your user type to do the right thing depending on the database capabilities. Hibernate itself takes a similar approach with its "native" ID generator, which behaves differently depending on the type of database you are using. An approach like this eliminates the need to switch the mapping at runtime.
For example, you could create one strategy class for each database. Then in your user type class, detect what database you're connected to when you're called for the first time, instantiate the proper strategy for that database, and then delegate all calls to the strategy object.
This answer is based on the other answers to this question and works with Hibernate 4.
Solution 1 for column definition with #Type(type = "org.hibernate.type.PostgresUUIDType")
Use this HSQL dialect:
import org.hibernate.boot.model.TypeContributions;
import org.hibernate.dialect.HSQLDialect;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.AbstractSingleColumnStandardBasicType;
import org.hibernate.type.PostgresUUIDType;
import org.hibernate.type.descriptor.java.UUIDTypeDescriptor;
import org.hibernate.type.descriptor.sql.VarcharTypeDescriptor;
public class UuidHsqlDialect extends HSQLDialect {
#Override
public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
super.contributeTypes(typeContributions, serviceRegistry);
typeContributions.contributeType(new AbstractSingleColumnStandardBasicType(VarcharTypeDescriptor.INSTANCE, UUIDTypeDescriptor.INSTANCE) {
#Override
public String getName() {
return PostgresUUIDType.class.getName();
}
});
}
}
Solution 2 for column definition with #Type(type = "pg-uuid")
Use this HSQL dialect:
import org.hibernate.boot.model.TypeContributions;
import org.hibernate.dialect.HSQLDialect;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.AbstractSingleColumnStandardBasicType;
import org.hibernate.type.descriptor.java.UUIDTypeDescriptor;
import org.hibernate.type.descriptor.sql.VarcharTypeDescriptor;
public class UuidHsqlDialect extends HSQLDialect {
#Override
public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
super.contributeTypes(typeContributions, serviceRegistry);
typeContributions.contributeType(new AbstractSingleColumnStandardBasicType(VarcharTypeDescriptor.INSTANCE, UUIDTypeDescriptor.INSTANCE) {
#Override
public String getName() {
return PostgresUUIDType.class.getName();
}
});
}
}
JPA configuration
Reference your new UuidHsqlDialect class in your (test) application.properties:
spring.jpa.properties.hibernate.dialect=<full-package-name>.UuidHsqlDialect