groovy.lang.MissingPropertyException: No such property for class
In previous article, we are using Groovy Templates for Spring Boot CRUD application. We have Movie entity:
...
@Entity
@Getter
@Setter
public class Movie implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@NotBlank
@Size(max = 255)
private String title;
private Integer releaseYear;
private Integer runtimeMinutes;
@Size(max = 255)
private String tags;
@Size(max = 50)
private String lang;
@Size(max = 50)
private String country;
}
Please refer here for full entity class.
Previously, this is the snippet for getMovieById(...)
function:
@GetMapping(value = "/movies/{movieId}")
public String getMovieById(Model model, @PathVariable long movieId) {
Movie movie = null;
String errorMessage = null;
try {
movie = movieService.findById(movieId);
} catch (Exception ex) {
errorMessage = "Movie not found";
}
model.addAttribute("movie", movie);
model.addAttribute("allowDelete", false);
model.addAttribute("errorMessage", errorMessage);
return "movie";
}
And this is a snippet of movie.tpl
:
yieldUnescaped '<!DOCTYPE html>'
html(lang:'en') {
head {
...
}
body {
...
div {
table(border: "0") {
tr {
td("Id")
td(":")
td(movie.id ?: '')
}
tr {
td("Title")
td(":")
td(movie.title ?: '')
}
tr {
td("Release Year")
td(":")
td(movie.releaseYear ?: '')
}
tr {
td("Runtime (Minutes)")
td(":")
td(movie.runtimeMinutes ?: '')
}
tr {
td("Tags")
td(":")
td(movie.tags ?: '')
}
tr {
td("Language")
td(":")
td(movie.lang ?: '')
}
tr {
td("Country")
td(":")
td(movie.country ?: '')
}
}
}
...
}
}
Check here for complete template source.
The Problem
When running the application and browse one movie, one example in http://localhost:8080/movies/2
, I got following error:
groovy.lang.MissingPropertyException: No such property: id for class: movie Possible solutions: out at groovy.lang.MetaClassImpl.invokeStaticMissingProperty(MetaClassImpl.java:1021) ~[groovy-2.5.8.jar:2.5.8] at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:1866) ~[groovy-2.5.8.jar:2.5.8] at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:1842) ~[groovy-2.5.8.jar:2.5.8] at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:3797) ~[groovy-2.5.8.jar:2.5.8] at org.codehaus.groovy.runtime.callsite.ClassMetaClassGetPropertySite.getProperty(ClassMetaClassGetPropertySite.java:50) ~[groovy-2.5.8.jar:2.5.8] at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGetProperty(AbstractCallSite.java:298) ~[groovy-2.5.8.jar:2.5.8] at movie$_run_closure1$_closure3$_closure4$_closure7$_closure8.doCall(movie.tpl:18) ~[na:na] at movie$_run_closure1$_closure3$_closure4$_closure7$_closure8.call(movie.tpl) ~[na:na]
When check in the internet, I find another people with similar problem:
Solution
The problem is because the name of the template we used. If we change template movie.tpl
into something else: movie-view.tpl
, and change getMovieById(...)
to return "movie-view".
@GetMapping(value = "/movies/{movieId}")
public String getMovieById(Model model, @PathVariable long movieId) {
...
model.addAttribute("movie", movie);
...
return "movie-view";
}
And when run it:
http://localhost:8080/movies/2
Problem solved! Maybe the engine confused since "movie" is used both as name of the template and model.