Search code examples
spring-bootkotlinthymeleafspring-el

Property or field 'isLPG' cannot be found on object of type 'com.rentautosofia.rentacar.bindingModel.CarBindingModel' - maybe not public?


I have an MVC logic like this one.

CarBindingModel

package com.rentautosofia.rentacar.bindingModel

import javax.validation.constraints.Size

class CarBindingModel(@Size(min = 1)
                      var name: String = "",
                      @Size(min = 1)
                      var price: Int = 0,
                      @Size(min = 1)
                      var imgURL: String = "",
                      var isLPG: Boolean? = false)

CarController

package com.rentautosofia.rentacar.controller.admin

import ...

const val PATH_ADMIN_CAR = "admin/car"
const val PATH_ADMIN_ALL_CARS = "$PATH_ADMIN_CAR/all"

@RequestMapping("/$PATH_ADMIN_CAR")
@Controller
class CarController @Autowired
constructor(private val carRepository: CarRepository) {

    @GetMapping("/create")
    fun create(model: Model): String {
        model.addAttribute("car", CarBindingModel())
        model.addAttribute("view", "$PATH_ADMIN_CAR/create")
        return "base-layout"
    }

    @PostMapping("/create")
    fun createProcess(model: Model, @Valid carBindingModel: 
CarBindingModel, bindingResult: BindingResult): String {
        if (bindingResult.hasErrors()) {
            model.addAttribute("view", "$PATH_ADMIN_CAR/create")
            model.addAttribute("message", "Invalid data.")
            model.addAttribute("car", carBindingModel)
            return "base-layout"
        }

        val car = car {
            name = carBindingModel.name
            price = carBindingModel.price
            imgURL = carBindingModel.imgURL
            isLPG = carBindingModel.isLPG
        }

        this.carRepository.saveAndFlush(car)
        return "redirect:/$PATH_ADMIN_ALL_CARS"
    }
...
}

CarView

The important one is this one (this is where I get an error)

<input  id="isLPG" type="checkbox" name="isLPG" th:checked="${car.isLPG}"/>

The problem is that I get a SpEL in my view. It says that It cannot find property isLPG in CarBindingModel.

The Error:

An error happened during template parsing (template: "class path resource [templates/base-layout.html]")
Caused by: org.attoparser.ParseException: Exception evaluating SpringEL expression: "car.isLPG" (template: "admin/car/create" - line 16, col 65)
Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "car.isLPG" (template: "admin/car/create" - line 16, col 65)
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1008E: 
Property or field 'isLPG' cannot be found on object of type 'com.rentautosofia.rentacar.bindingModel.CarBindingModel' - maybe not public?
org.springframework.expression.spel.SpelEvaluationException: EL1008E: 
Property or field 'isLPG' cannot be found on object of type 'com.rentautosofia.rentacar.bindingModel.CarBindingModel' - maybe not public?

I am basically trying to bind a boolean value from this checkbox. If you need additional details, I will happily add them.


Solution

  • It looks like SpEL is confused by the is prefix.

    This works

    package foo
    
    class CarBindingModel(
                      var name: String = "",
    
                      var price: Int = 0,
    
                      var imgURL: String = "",
    
                      var LPG: Boolean? = false)
    

    and

    public class So49863132Application {
    
        public static void main(String[] args) {
            CarBindingModel car = new CarBindingModel("Lexus", 42, "img.png", true);
            Expression exp = new SpelExpressionParser().parseExpression("name + ' ' + price + ' ' + LPG");
            System.out.println(exp.getValue(car));
        }
    
    }
    

    and

    Lexus 42 true
    

    EDIT

    It's due to the way Kotlin creates the getter; for isLPG, kotlin generates isLPG().

    SpEL is expecting isIsLPG().