'play framework'에 해당되는 글 2

  1. 2013.07.27 [ValidationException: HV000041: Call to TraversableResolver.isReachable() threw an exception.]
  2. 2013.07.27 Your first Play application

[ValidationException: HV000041: Call to TraversableResolver.isReachable() threw an exception.]

Play Framework todolist 예제를 따라하다가 발생한 에러


검색해보면 setter/getter를 추가해라는 답변도 있는데, 콘솔 에러를 보면
! @6f4fl4mol - Internal server error, for (POST) [/tasks] ->

play.api.Application$$anon$1: Execution exception[[ValidationException: HV000041: Call to TraversableResolver.isReachable() threw an exception.]]
        at play.api.Application$class.handleError(Application.scala:289) ~[play_2.10.jar:2.1.2]
    ...
        at org.hibernate.validator.internal.engine.ValidatorImpl.validate(ValidatorImpl.java:133) ~[hibernate-validator.jar:4.3.0.Final]
Caused by: java.lang.RuntimeException: No @javax.persistence.Id field found in class [class models.Task]
        at play.db.ebean.Model._idAccessors(Model.java:54) ~[play-java-ebean_2.10.jar:2.1.2]
        at play.db.ebean.Model._getId(Model.java:67) ~[play-java-ebean_2.10.jar:2.1.2]
        at play.db.ebean.Model.hashCode(Model.java:208) ~[play-java-ebean_2.10.jar:2.1.2]
        at org.hibernate.validator.internal.engine.resolver.SingleThreadCachedTraversableResolver$TraversableHolder.buildHashCode(SingleThreadCachedTraversableResolver.java:153) ~[hibernate-validator.jar:4.3.0.Final]
        at org.hibernate.validator.internal.engine.resolver.SingleThreadCachedTraversableResolver$TraversableHolder.<init>(SingleThreadCachedTraversableResolver.java:114) ~[hibernate-validator.jar:4.3.0.Final]
        at org.hibernate.validator.internal.engine.resolver.SingleThreadCachedTraversableResolver$TraversableHolder.<init>(SingleThreadCachedTraversableResolver.java:96) ~[hibernate-validator.jar:4.3.0.Final]

1.X 문서에서는 Play Model 클래스에서 @Id를 제공한다고 해서, @Id를 넣지 않아서 발생했다.

Your first Play application

http://www.playframework.com/documentation/2.1.x/JavaTodoList

Play 2.1.2
아주 간단한 예제

> play new todolist //프로젝트 생성
> cd todolist
> play
[todolist] $ run
package controllers;

import play.*;
import play.mvc.*;

import views.html.*;

public class Application extends Controller {
 
    public static Result index() {
//        return ok(index.render("Your new application is ready."));
        return ok("Hello world");
    } 
}


There is no need to compile the code yourself or restart the server to see the modification. It is automatically reloaded when a change is detected.

- 라우팅 추가
conf/routes
# Home page
GET     /                             controllers.Application.index()
                               
# Tasks         
GET     /tasks                      controllers.Application.tasks()
POST    /tasks                    controllers.Application.newTask()
POST    /tasks/:id/delete       controllers.Application.deleteTask(id: Long)
public class Application extends Controller {
 
  public static Result index() {
    return ok(index.render("Your new application is ready."));
  }
 
  public static Result tasks() {
    return TODO;
  }
 
  public static Result newTask() {
    return TODO;
  }
 
  public static Result deleteTask(Long id) {
    return TODO;
  } 
}
public static Result index() {
  return redirect(routes.Application.tasks());
}

- Task 모델
package models;

import java.util.List;
import java.util.ArrayList;

public class Task{

    public Long id;
    public String label;

    public static List<Task> all(){
        return new ArrayList<Task>();
    }

    public static void create(Task task){

    }

    public static void delete(Long id){

    }
}

- 템플릿 수정
index.scala.html
@(tasks: List[Task], taskForm: Form[Task])

@import helper._

@main("Todo list") {
   
    <h1>@tasks.size() task(s)</h1>
   
    <ul>
        @for(task <- tasks) {
            <li>
                @task.label
               
                @form(routes.Application.deleteTask(task.id)) {
                    <input type="submit" value="Delete">
                }
            </li>
        }
    </ul>
   
    <h2>Add a new task</h2>
   
    @form(routes.Application.newTask()) {
       
        @inputText(taskForm("label"))
       
        <input type="submit" value="Create">
       
    }
   
}
import play.data.*;

import views.html.*;

import models.*;

public class Application extends Controller {
 
	static Form<Task> taskForm = Form.form(Task.class);
import play.data.validation.Constraints.*;

public class Task {
    
  public Long id;
  
  @Required
  public String label;

- Rendering the first page
public class Application extends Controller {
  ...
  public static Result tasks() {
    return ok( //200 OK
      views.html.index.render(Task.all(), taskForm)
    );
  }


- form 전송 처리
public class Application extends Controller {
  ...
  public static Result newTask() {
    Form<Task> filledForm = taskForm.bindFromRequest();
    if(filledForm.hasErrors()) {
      return badRequest( //400 Bad Request
        views.html.index.render(Task.all(), filledForm)
      );
    } else {
      Task.create(filledForm.get());
      return redirect(routes.Application.tasks()); 
    }
  }
- 데이터베이스 처리
conf/application
db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:mem:play"
...
ebean.default="models.*"
서버 재시작할 필요없음.

EBean (Play’s default ORM) 사용
package models;

import java.util.List;
import java.util.ArrayList;

import play.db.ebean.*;
import play.data.validation.Constraints.*;

import javax.persistence.*;

@Entity
public class Task extends Model{

	@Id
	public Long id;

	@Required
	public String label;

	public static Finder<Long, Task> find = new Finder(
		Long.class, Task.class
	);

	public static List<Task> all(){
//		return new ArrayList<Task>();
		return find.all();
	}

	public static void create(Task task){
		task.save();
	}

	public static void delete(Long id){
		find.ref(id).delete();
	}
}

- 삭제 기능
public class Application extends Controller {

	public static Result deleteTask(Long id){
//		return TODO;
		Task.delete(id);
		return redirect(routes.Application.tasks());
	}

- Heroku에 배포
...다음 기회에