views:

1841

answers:

2

Hi! I am a newbie at Groovy and I want to modify one example I've found at the Internet (the blog one). I've defined two classes Post and Comment as follows:

class Post {    

static hasMany = [comments:Comment]

String title
String teaser
String content    
Date lastUpdated

SortedSet comments

static constraints = {
    title(nullable:false, blank:false, length:1..50)
    teaser(length:0..100)
    content(nullable:false, blank:false)
    lastUpdated(nullable:true)

}

String toString() {title} 
}

Post post
String comment
String name
String url
String email
Date dateCreated = new Date()


static belongsTo = Post

static constraints = {
    comment(nullable:false, blank:false)
 name(nullable:false, blank:false)
    url(nullable:true, blank:true, url:true)
    email(nullable:true, blank:true, email:true) 
    dateCreated(nullable:true)
    post(nullable:false)
}

public int compareTo(Object o) {
    return dateCreated.compareTo(o.dateCreated)
}

String toString() {comment}
}

Up to now all OK.

I've defined the controllers as follows:

class CommentController {

def edit = {
    render(view:'edit',
        model:[ comment:new Comment(),
                postId:params.postId])        
}

def save = {
    def comment = new Comment(params)
    comment.dateCreated = new Date()
    comment.post = Post.get(params.postId)   

    if(comment.save()) {        
        redirect(
                controller:'post',
                action:'list',
                id:params.postId)
    } 
}

}

class PostController {

def defaultAction = 'list'

def index = {
    render("En el norte de Alabama")
}

def edit = {
    render(view:'edit', model:[post:loadPost(params.id)])
}

def save = {
    def post = loadPost(params.id)
    post.lastUpdated = new Date()

    post.properties = params
    if(post.save()) {
        print "id " + post.id + "\n"     
        def offset = post.id - 1
        print "offset " + offset

        redirect(action:'list', offset:offset)
    } else {
        render(view:'edit', model:[post:post])
    }
}

def list = {
    if(!params.max)params.max = 1

    [ postList: Post.list( params ) ]

}


def view = {
    render(view:'view', model:[post:Post.get(params.id)])
}

private loadPost(id) {
    def post = new Post();
    if(id) {
        post = Post.get(id)
    }
    return post
}
}

Finally I've defined the views/post/list

as follows:

<%@ page contentType="text/html;charset=UTF-8" %>
<html>
  <head><title>My postList</title>
  </head>
     <body>
        <div class="nav">
    <g:link controller="post" action="edit">New post</g:link>            
        </div>
          <span class="menuButton"><H1>Last posts</H1></span> 

 <table border = 1><tr><td>

<g:each in="${postList}" var="post">
 <div>
   <h2>${post.title}</h2>
       <p>Last update: <g:formatDate date="${post.lastUpdated}" 
          format="yyyy-MMM-dd HH:mm"/></p>
 <p><i>${post?.content}</i></p>  
 </div>

 <div class="paginateButtons">
    <g:link controller="comment" action="edit" params="[postId:post.id]">
    Add comment    
    </g:link>            
</div> 


   <g:each in="${post.comments}" var="comt">        
     ${comt.comment} <br />
   </g:each>     
</g:each>
<td></tr></table>


 <div class="paginateButtons">
        <g:paginate max="1" next="Next" prev="Prev." 
           total="${postCount == null ? Post.count(): postCount}" />
</div>   
</body>
</html>

I can generate new Posts without any problem, but when I want to put comments to my posts I can put at most ONE comment for each post. When trying to put more I get a ClassCastException as follows:

Message: Comment
Caused by: Error processing GroovyPageView: Comment
Class: /WEB-INF/grails-app/views/post/list.gsp
At Line: [-1] 

org.codehaus.groovy.grails.web.pages.exceptions.GroovyPagesException: Error processing GroovyPageView: Comment

    at org.codehaus.groovy.grails.web.servlet.view.GroovyPageView.handleException(GroovyPageView.java:134)

    at org.codehaus.groovy.grails.web.servlet.view.GroovyPageView.renderWithTemplateEngine(GroovyPageView.java:112)

    at org.codehaus.groovy.grails.web.servlet.view.GroovyPageView.renderMergedOutputModel(GroovyPageView.java:86)

    at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:257)

    at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1183)

    at org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet.doDispatch(GrailsDispatcherServlet.java:294)

    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)

    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)

    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:501)

    at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)

    at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)

    at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:502)

    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1124)

    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:70)

    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1115)

    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:70)

    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1115)

    at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:361)

    at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)

    at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)

    at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:766)

    at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:417)

    at org.mortbay.jetty.servlet.Dispatcher.forward(Dispatcher.java:334)

    at org.mortbay.jetty.servlet.Dispatcher.forward(Dispatcher.java:126)

    at org.codehaus.groovy.grails.web.util.WebUtils.forwardRequestForUrlMappingInfo(WebUtils.java:293)

    at org.codehaus.groovy.grails.web.util.WebUtils.forwardRequestForUrlMappingInfo(WebUtils.java:269)

    at org.codehaus.groovy.grails.web.util.WebUtils.forwardRequestForUrlMappingInfo(WebUtils.java:261)

    at org.codehaus.groovy.grails.web.mapping.filter.UrlMappingsFilter.doFilterInternal(UrlMappingsFilter.java:181)

    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)

    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1115)

    at org.codehaus.groovy.grails.web.sitemesh.GrailsPageFilter.obtainContent(GrailsPageFilter.java:171)

    at org.codehaus.groovy.grails.web.sitemesh.GrailsPageFilter.doFilter(GrailsPageFilter.java:110)

    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1115)

    at org.codehaus.groovy.grails.web.servlet.filter.GrailsReloadServletFilter.doFilterInternal(GrailsReloadServletFilter.java:101)

    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)

    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1115)

    at org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequestFilter.doFilterInternal(GrailsWebRequestFilter.java:65)

    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)

    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1115)

    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:96)

    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)

    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:236)

    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)

    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1115)

    at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:361)

    at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)

    at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)

    at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:766)

    at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:417)

    at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)

    at org.mortbay.jetty.Server.handle(Server.java:324)

    at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:534)

    at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:864)

    at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:533)

    at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:207)

    at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:403)

    at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)

    at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:522)

Caused by: java.lang.ClassCastException: Comment

    at java.util.TreeMap.compare(TreeMap.java:1093)

    at java.util.TreeMap.put(TreeMap.java:465)

    at java.util.TreeSet.add(TreeSet.java:210)

    at java.util.AbstractCollection.addAll(AbstractCollection.java:318)

    at java.util.TreeSet.addAll(TreeSet.java:258)

    at D__Workspace_groovypublish_grails_app_views_post_list_gsp$_run_closure5.doCall(D__Workspace_groovypublish_grails_app_views_post_list_gsp:52)

    at D__Workspace_groovypublish_grails_app_views_post_list_gsp.run(D__Workspace_groovypublish_grails_app_views_post_list_gsp:21)

Seems to be that the problem is at the list.gsp file when trying to put nested "each"s

Any hint

Thanks in advance

Luis

+4  A: 

Well, from what I can read here, you're using SortedSet as your container type for Comments in a Post. This is fine, but you have to make Comments implement Comparable, as that's a requirement for all SortedSet-contained objects. You'd probably want your comments sorted by dateCreated anyway, so you have to SAY that somewhere (like in the compareTo function you'll need to satisfy the interface).

Any reason you're not just using a List? Seems like you wouldn't want to add Comments with earlier dates anyway.

Anyway, if this isn't it, comment and I'll take a longer look.

Bill James
I've forgotten to post the "Comment" class.Now I've got it working.The problem was at both places: The Post and the CommentController.At the Post Class the I've defined comments as a List and not as a SortedSet. At the CommentController I've added this code. comment.post = Post.get(params.postId) post.addToComments(comment)Now is working.thanks you for your comments without them I could't get it runningBTW, amazon is delivering next week the Groovy books I#ve ordered :-)
Luixv
A: 

I agree with Bill James but I think that you should note am improvement in your analysis of this problem. Your post had good data surrounding your question. In fact you had everything you needed. Lets look at that stacktrace.

Here is the code from TreeMap.java: 1093

private int compare(K k1, K k2) {
    return (comparator==null ? ((Comparable</*-*/K>)k1).compareTo(k2)
                             : comparator.compare((K)k1, (K)k2));
}

From here you can see that Comment being cast to Comparable was the problem. A little look into TreeMap, TreeSet and Comparable would have probably pushed you through this problem.

Please don't interpret this post as in anyway impugning your question or problem. Your question is good, and well asked. This hopefully is another bit of data in helping you learn to fish.

Nathan Feger