Strange thing in Play 1.2.x when working with database - java

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.)

Related

How to access java object methods returned value in thymeleaf template

Tried to get the returned value of the method in thymeleaf template but faced an issue. following is the environment
Controller class :
#Component
#Controller
public class HighController {
#GetMapping("/abcdata")
public String customerForm(Model model) throws IOException, InterruptedException {
model.addAttribute("abcdata", new CostDataModel());
return "abcdata";
}
}
getter and setter
import java.util.List;
import org.springframework.stereotype.Component;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
#Setter
#Getter
#NoArgsConstructor
#Component
public class CostDataModel {
public SubList abcdata;
}
Main Class
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;
#ComponentScan
#SpringBootApplication
public class AbcmanagementApplication {
public static void main(String[] args) {
SpringApplication.run(CostmanagementApplication.class, args);
}
}
thymeleaf template view (abcdata.html)
<div class="starter-template">
<form action="#" th:action="#{/abcdata}" th:object="${abcdata}" method="post">
<div class="form-group">
<label for="subs">Choose subs</label>
<select class="form-control selectpicker" th:field="*{abcdata}" id="abcdata">
<option value="">Nothing selected</option>
<option th:each="abcdata : ${abcdata}"
th:value="${abcdata.abcdata}"
th:text="${abcdata}">abcdata
</option>
</select>
</div>
<button class="btn btn-primary" type="submit">Submit form</button>
</form>
</div>
SubList class
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
#Component
public class SubList {
#Autowired
private RequestToken rt;
public List<String> getSub() throws IOException, InterruptedException
{
// some code here
return list;
}
}
I need to access the entire list returned by the getSub() method in the thymeleaf template. but instead of list, it is returning the entire object. In thymeleaf, I am using drop down field to populate entire list but some issue.
Start by removing #Component from the objects that you put in the Model (so CostDataModel and SubList). This annotation means that you want the Spring container to create a single instance, but this is not want you want here.
Remove #Component from HighController. You already have #Controller which is enough to have Spring pick up the class as a singleton with component-scanning.
What is the use of RequestToken inside SubList? As SubList is not a Spring singleton anymore, the autowiring will not work. If you really need it, maybe pass it manually via the constructor.
With th:object="${abcdata}", you select the CostDataModel instance in Thymeleaf. When you do th:field="*{abcdata}" in the <select>, it means that Thymeleaf will call the getAbcData() method on the selected CostDataModel, which returns the SubList instance. This is not what you want, you should use simple String field. It is a bit hard to guess what the exact solution is to your question, maybe you can use some better names than abcdata everywhere to better understand your question. In any case, you might want read about Using HTML select options with Thymeleaf on my blog to understand more about this and then maybe update your question if things are still not working.
This is how I resolved it. Instead of creating the new instance of CostDataModel () and passing as model attribute , copied the entire method code of getSub() in the controller class. see below
#Controller
public class HighController {
#GetMapping("/abcdata")
public String customerForm(Model model) throws IOException, InterruptedException {
// all the code of getSub() method
model.addAttribute("abcdata", abcdata);
return "abcdata";
}
}

What import statements am I missing to get this class to connect this couchbase server with my REST API?

I'm trying to connect a local Couchbase server with a Spring Boot REST API I'm building. The code I'm using is from the bottom of in the usage section: http://projects.spring.io/spring-data-couchbase/#quick-start
I think I have everything configured, I just can't get this last class to function without errors. I believe it's all related to having proper import statements, which I've only been able to figure out a few. The "user" object is having issues instantiating, stating it's abstract. Several functions based off that are therefore throwing errors. Box and Point also seem to not be able to agree on an import statement. I can only get one of them fixed at a time.
Here is the code for the class, I don't think you'll need anything from other classes:
package hello;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.swing.*;
import java.util.List;
#Service
public class MyService {
private final UserRepository userRepository;
#Autowired
public MyService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public void doWork() {
userRepository.deleteAll();
User user = new User();
user.setLastname("Jackson");
user.setLocation(new Point(123, 456));
user = userRepository.save(user);
List<User> jacksonChildren =
userRepository.findByLastNameAndAgeBetween("Jackson", 0, 18);
List<User> jacksonFamily =
userRepository.findByLastName("Jackson");
//bounding box is lower-left, upper-right corners
Box cityBounds = new Box(new Point(100, 100), new Point(150, 500));
List<User> jacksonsInSomeCity =
userRepository.findByLocationWithin(cityBounds);
}
}
User entity needs to be defined in your project. The reference documentation has an example http://docs.spring.io/spring-data/couchbase/docs/2.1.6.RELEASE/reference/html/#basics. Here is a sample project using Couchbase in spring boot https://github.com/spring-projects/spring-boot/tree/master/spring-boot-samples/spring-boot-sample-data-couchbase.

Using Spring Security ACL

I am trying to implement Spring Security ACL in my application. I have many classes that I want to use an ACL on.
I read in the documentation that AOP have been used with success before. Does this mean that all the services should have a common interface for doing CRUD against the objects for maximum reuse of the advise?
Or is it normal to manually insert, delete, ... in the save, update, delete methods of the service?
I can't manage to find many examples of how people use the framework.
---- Listener for Entity removal (includes cascading deletes) -----
package com.acme.model.aspects;
import javax.annotation.PostConstruct;
import javax.persistence.PreRemove;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.data.domain.Persistable;
import com.acme.PermissionService;
#Component
public class ObjectIdentityListener {
private static final Logger LOG = LoggerFactory.getLogger(ObjectIdentityListener.class);
static private PermissionService permissionService;
#Autowired(required = true)
#Qualifier("permissionService")
public void setSearchService(PermissionService _permissionService)
{
permissionService = _permissionService;
}
#PreRemove
public void preRemove(Object object) {
if(object instanceof Persistable) {
LOG.info("Deleting object identity for class {} id {} ", persistable.getClass(), persistable.getId());
permissionService.deleteObjectIdentity((Persistable) object);
}
}
#PostConstruct
public void init() {
Assert.notNull(permissionService, "'permissionService' is required");
}
}
---- Delete method for permissionService ----
public void deleteObjectIdentity(Persistable persistable) {
try{
MutableAcl acl = (MutableAcl) mutableAclService.readAclById(identity(persistable));
mutableAclService.deleteAcl(acl.getObjectIdentity(), true);
} catch (NotFoundException e){
LOG.info("Could not find ACL for target {}", persistable);
}
}
It all depends on your app. Having a centralized hierarchy of services would certainly make it simpler to implement single security checks for create/retrieve/update/delete methods. But you have an existing app with different services that don't necessarily have a common parent implementation, then you'd have to add ALC security annotation on each service method.
Another option is to put ACL security on your DAO layer, it works fine, but for some reason just doesn't feel right. IMHO DAO's shouldn't deal with things like security. I've spent a LOT of time dealing with Spring Security ACL, got a pretty good handle on it by now, ping me if you need any concrete examples.

Play Framework Does Not Create Models

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.

how to import java extensions in a play framework model?

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);

Categories

Resources