Error 'org.thymeleaf.spring4.processor.attr.SpringOptionFieldAttrProcessor' when posting object from form with ThymeLeaf and Spring MVC

0

This is my class FisicHost.java :

// Remove imports and getter / setters to make it shorter

@Entity
@Transactional
public class FisicHost {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne(fetch=FetchType.EAGER)
    private Datacenter datacenter;

    @OneToMany(mappedBy = "fisicHost")
    @LazyCollection(LazyCollectionOption.FALSE)
    private List<Credential> credentials;

    private String name;
    private String ip;
    private String operatingSystem;
    private String notes;

    public FisicHost(){

    }

    public FisicHost(Long id, Datacenter datacenter, List<Credential> credentials, String name, String ip, String operatingSystem, String notes) {
        this.id = id;
        this.datacenter = datacenter;
        this.credentials = credentials;
        this.name = name;
        this.ip = ip;
        this.operatingSystem = operatingSystem;
        this.notes = notes;
    }
}

This is my class Datacenter.java :

@Entity
@Transactional
public class Datacenter {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    private String name;

    @OneToMany(mappedBy = "datacenter")
    @LazyCollection(LazyCollectionOption.FALSE)
    private List<FisicHost> fisicHostList;

    public Datacenter(){

    }

    public Datacenter(int id, String name, List<FisicHost> fisicHostList) {
        this.id = id;
        this.name = name;
        this.fisicHostList = fisicHostList;
    }
}

This is my form to add FisicHost's to a Datacenter ...

        <form action="/hostFisicos" method="post" th:object="${fisicHost}">

            <div class="form-control">
                <label for="nombre">Nombre</label>
                <input type="text" name="nombre" id="nombre" th:field="*{name}" class="form-group" required="required"/>
            </div>

            <br/><br/><br/>

            <div class="form-control">
                <label for="ip">Ip</label>
                <input type="text" name="ip" id="ip" th:field="*{ip}" class="form-group" required="required"/>
            </div>

            <br/><br/><br/>

            <div class="form-control">
                <label for="sistemaOperativo">Sistema Operativo</label>
                <select type="text" name="sistemaOperativo" id="sistemaOperativo" th:field="*{operatingSystem}" class="form-group">
                    <option value="Windows">Windows</option>
                    <option value="Linux">Linux</option>
                </select>
            </div>

            <br/><br/><br/>

            <div class="form-control">
                <label for="datacenter">Datacenter</label>
                <select type="text" name="datacenter" id="datacenter" th:field="*{datacenter}" class="form-group">
                    <option th:each="datacenter : ${allDatacenters}" th:text="${datacenter.name}" th:value="${datacenter}"></option>
                </select>
            </div>

            <!--<p th:field="*{datacenter}" th:each="datacenter : ${allDatacenters}" th:text="${datacenter.name}" th:value="${datacenter}"></p>-->

            <br/><br/><br/>

            <div class="form-control">
                <label for="notas">Notas</label>
                <textarea name="notas" id="notas" th:field="*{notes}" cols="30" rows="10" class="form-group"></textarea>
            </div>

            <br/><br/><br/>

            <button type="submit" class="btn btn-success">AGREGAR</button>
        </form>

Well ... this was fine until it occurred to me to put a <select> with the Datacenter list so that the user can choose which Datacenter wants to add that FisicHost ...

More precisely this happens in this template code block:

   <div class="form-control">
                <label for="datacenter">Datacenter</label>
                <select type="text" name="datacenter" id="datacenter" th:field="*{datacenter}" class="form-group">
                    <option th:each="datacenter : ${allDatacenters}" th:text="${datacenter.name}" th:value="${datacenter}"></option>
                </select>
            </div>

The idea, to be understood better is to do something like this:

But with the code that I shared so far I get this error when doing the form submit

  

There was an unexpected error (type = Bad Request, status = 400).   Validation failed for object = 'physicalHost'. Error count: 1

Then googling a bit I found that I have to do some strange things to format the Datacenter .... and following this tutorial I added this class to my model:

DatacenterFormatter.java :

@Component
public class DatacenterFormatter implements Formatter<Datacenter> {

    @Autowired
    DatacenterService datacenterService;

    @Override
    public Datacenter parse(String name, Locale locale) throws ParseException {
        return datacenterService.getDatacenterByName(name);
    }

    @Override
    public String print(Datacenter datacenter, Locale locale) {
        return datacenter.getName();
    }
}

and my controller happened to look like this:

// Metodo que recibe el POST del formulario y guarda el Objeto en BD
@RequestMapping(value = "/hostFisicos", method = RequestMethod.POST)
    public String guardarHostFisico(@ModelAttribute("fisicHost") @Valid FisicHost fisicHost){
    fisicHostService.save(fisicHost);
    return "redirect:/hostFisicos";
}

but when doing the submit I still have an error, this time by console, which says the following:

  

org.hibernate.TypeMismatchException: Provided id of the wrong type for   class com.amco.Datacenter.model.Datacenter. Expected: class   java.lang.Integer, got class java.lang.String

I understand that you are waiting for an Integer and I am sending you a String, but I do not have the faintest idea where the error might come from ....

Someone with experience that can guide me or give me a hand?

Thank you very much:)

    
asked by Nacho Zve De La Torre 28.11.2018 в 17:00
source

1 answer

0

I leave the solution for anyone who reads this in the future ...

It was VERY easy:

@Override
public Datacenter parse(String name, Locale locale) throws ParseException {
    int id = Integer.parseInt(name);
    return datacenterService.getDatacenterById(id);
}

you had to pause int the String of the interface ...

    
answered by 28.11.2018 в 17:34