Home > Blockchain >  Convert String to Money Thymeleaf
Convert String to Money Thymeleaf

Time:06-17

I am having a problem converting input String to money. I am creating a spring boot application with thymeleaf. I have a web page where user inputs the data and there is a particular field where he inputs the String and it needs to be converted to type joda.money as in my pojo class that field has money data type. This is a full governor_form.html:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>[[${pageTitleG}]]</title>
    <link rel="stylesheet" type="text/css" th:href="@{/webjars/bootstrap/css/bootstrap.min.css}"/>
</head>
<body>
<div >
    <div ><h2>[[${pageTitleG}]]</h2></div>
    <form th:action="@{/governors/save}" method="post" th:object="${governor}" style="max-width: 550px; margin: 0 auto;">
        <input type="hidden" th:field="*{idGovernor}">
        <div >
            <div >
                <label >Full name:</label>
                <div >
                    <input type="text" th:field="*{fullName}"  required minlength="5" maxlength="70">
                </div>
            </div>
            <div >
                <label >Age</label>
                <div >
                    <input type="number" step="0.01" th:field="*{age}"  required>
                </div>
            </div>
            <div >
                <label >Position</label>
                <div >
                    <input type="text" step="0.01" th:field="*{position}"  required>
                </div>
            </div>
            <div >
                <label >Date of Intercession</label>
                <div >
                    <input type="date" th:field="*{dateOfIntercession}" >
                </div>
            </div>
            <div >
                <label >Date of Resignation</label>
                <div >
                    <input type="date" th:field="*{dateOfResignation}" >
                </div>
            </div>
            <div >
                <label >Per Capita Income</label>
                <div >
                    <input type="number" step="0.01" th:field="*{perCapitaIncome}"  required>
                </div>
            </div>
            <div >
                <label >Population Below Poverty</label>
                <div >
                    <input type="number" step="0.01" th:field="*{populationBelowPoverty}"  required min="0" max="99">
                </div>
            </div>
            <div >
                <label >State</label>
                <div >
                    <select th:field="*{state}"  required>
                        <th:block th:each="state : ${listStates}">
                            <option th:text="${state.officialStateName}" th:value="${state.idState}"/>
                        </th:block>
                    </select>
                </div>
            </div>
            <div >
                <button type="submit" >Save</button>
                <button type="button"  onclick="cancelForm()">Cancel</button>
            </div>
        </div>
    </form>
</div>
<script type="text/javascript">
    function cancelForm() {
        window.location = "[[@{/governors}]]";
    }
</script>
</body>
</html>

This is where he inputs that data:

<div >
     <label >Per Capita Income</label>
     <div >
          <input type="number" step="0.01" th:field="*{perCapitaIncome}"  required>
     </div>
</div>

So if i'm not mistaken Hibernate is having a problem converting a String input from thymeleaf to type money as I get the following error:

: Resolved [org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors<EOL>Field error in object 'governor' on field 'perCapitaIncome': rejected value [1100]; codes [typeMismatch.governor.perCapitaIncome,typeMismatch.perCapitaIncome,typeMismatch.org.joda.money.Money,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [governor.perCapitaIncome,perCapitaIncome]; arguments []; default message [perCapitaIncome]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'org.joda.money.Money' for property 'perCapitaIncome'; Cannot convert value of type 'java.lang.String' to required type 'org.joda.money.Money' for property 'perCapitaIncome': no matching editors or conversion strategy found]]

This is the joda.money dependency:

<dependency>
     <groupId>org.joda</groupId>
     <artifactId>joda-money</artifactId>
     <version>1.0.1</version>
</dependency>

This is a POJO class:

@Entity
@Table(name = "governor")
public class Governor implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id_governor")
private Integer idGovernor;

@Column(name = "pib")
private String fullName;

@Column(name = "age")
private Integer age;

@Column(name = "position")
private String position;

@Column(name = "date_of_intercession")
private java.sql.Date dateOfIntercession;

@Column(name = "date_of_resignation")
private java.sql.Date dateOfResignation;

@Column(name = "per_capita_income")
private Money perCapitaIncome;

@Column(name = "population_below_poverty")
private Integer populationBelowPoverty;

@ManyToOne
@JoinColumn(name = "id_state", nullable = false)
private State state;

public State getState() {return state;}

public void setState(State state) {this.state = state;}

public Integer getIdGovernor() {
    return this.idGovernor;
}

public void setIdGovernor(Integer idGovernor) {
    this.idGovernor = idGovernor;
}

public String getFullName() {
    return this.fullName;
}

public void setFullName(String fullName) {this.fullName = fullName;}

public Integer getAge() {
    return this.age;
}

public void setAge(Integer age) {
    this.age = age;
}

public String getPosition() {
    return this.position;
}

public void setPosition(String position) {
    this.position = position;
}

public java.sql.Date getDateOfIntercession() {
    return this.dateOfIntercession;
}

public void setDateOfIntercession(java.sql.Date dateOfIntercession) {
    this.dateOfIntercession = dateOfIntercession;
}

public java.sql.Date getDateOfResignation() {
    return this.dateOfResignation;
}

public void setDateOfResignation(java.sql.Date dateOfResignation) {
    this.dateOfResignation = dateOfResignation;
}

public Money getPerCapitaIncome() {
    return this.perCapitaIncome;
}

public void setPerCapitaIncome(Money perCapitaIncome) {
    this.perCapitaIncome = perCapitaIncome;
}

public Integer getPopulationBelowPoverty() {
    return this.populationBelowPoverty;
}

public void setPopulationBelowPoverty(Integer populationBelowPoverty) {
    this.populationBelowPoverty = populationBelowPoverty;
}
}

This is a controller:

@Controller
public class GovernorController {
@Autowired
GovernorService governorService;

@Autowired
GovernorRepository governorRepository;

@Autowired
StateRepository stateRepository;
@Autowired
StateService stateService;

@GetMapping("/governors")
public String showAllGovernors(Model model){
    List<Governor> listGovernors = governorService.findAllGovernors();
    model.addAttribute("listGovernors", listGovernors);
    return "governors";
}

@GetMapping("/governors/new")
public String showNewGovernorForm(Model model){
    List <State>  listStates = stateService.findAll();
    model.addAttribute("listStates", listStates);
    model.addAttribute("governor", new Governor());
    model.addAttribute("pageTitleG", "Add New Governor");
    return "governor_form";
}

@PostMapping("/governors/save")
public String saveGovernor (Governor requestGovernor, RedirectAttributes redirectAttributes){
    governorRepository.save(requestGovernor);
    redirectAttributes.addFlashAttribute("messageG", "The governor has been saved successfully!");
    return "redirect:/governors";
}

@GetMapping("/governors/edit/{id}")
public String showEditGovernorForm(@PathVariable("id") Integer id, Model model, RedirectAttributes redirectAttributes){
    try {
        Governor governor = governorService.findGovernorById(id);
        List <State>  listStates = stateService.findAll();
        model.addAttribute("listStates", listStates);
        model.addAttribute("governor", governor);
        model.addAttribute("pageTitleG", "Edit Governor (ID: "   id   ")");
        return "governor_form";
    } catch (EntityNotFoundException e) {
        redirectAttributes.addFlashAttribute("messageG", e.getMessage());
        return "redirect:/governors";
    }
}

@GetMapping("/governors/delete/{id}")
public String deleteGovernor(@PathVariable("id") Integer id, Model model, RedirectAttributes redirectAttributes){
    try {
        governorService.deleteGovernor(id);
        redirectAttributes.addFlashAttribute("messageG", "The governor ID "   id   " has been deleted!");
    } catch (StateNotFoundException e) {
        redirectAttributes.addFlashAttribute("messageG", e.getMessage());
    }
    return "redirect:/governors";
}

}

How do I convert String to Money?

CodePudding user response:

One solution would be to create custom deserilizer for Money field, and then use Jackson to set it.

Here is code snippet:

MoneyDeserializer.java :

public class MoneyDeserializer extends StdDeserializer<BigMoney> {

    private static final long serialVersionUID = 2518470236548239933L;


    public MoneyDeserializer() {
        super(Money.class);
    }

    @Override
    public BigMoney deserialize(final JsonParser jp, final DeserializationContext ctxt) throws IOException, JsonProcessingException {
        return BigMoney.of(CurrencyUnit.USD, jp.readValueAs(Double.class));
    }
}

Governor.java

import com.example.demo.filter.MoneyDeserializer;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import org.joda.money.BigMoney;
import org.joda.money.Money;

import java.io.Serializable;


public class Governor implements Serializable {

    private Integer idGovernor;


    private String fullName;


    private Integer age;


    private String position;


    private java.sql.Date dateOfIntercession;


    private java.sql.Date dateOfResignation;



    private BigMoney perCapitaIncome;


    private Integer populationBelowPoverty;




    public Integer getIdGovernor() {
        return this.idGovernor;
    }

    public void setIdGovernor(Integer idGovernor) {
        this.idGovernor = idGovernor;
    }

    public String getFullName() {
        return this.fullName;
    }

    public void setFullName(String fullName) {this.fullName = fullName;}

    public Integer getAge() {
        return this.age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getPosition() {
        return this.position;
    }

    public void setPosition(String position) {
        this.position = position;
    }

    public java.sql.Date getDateOfIntercession() {
        return this.dateOfIntercession;
    }

    public void setDateOfIntercession(java.sql.Date dateOfIntercession) {
        this.dateOfIntercession = dateOfIntercession;
    }

    public java.sql.Date getDateOfResignation() {
        return this.dateOfResignation;
    }

    public void setDateOfResignation(java.sql.Date dateOfResignation) {
        this.dateOfResignation = dateOfResignation;
    }

    public BigMoney getPerCapitaIncome() {
        return this.perCapitaIncome;
    }
    @JsonDeserialize(using = MoneyDeserializer.class)
    public void setPerCapitaIncome(BigMoney perCapitaIncome) {
        this.perCapitaIncome = perCapitaIncome;
    }

    public Integer getPopulationBelowPoverty() {
        return this.populationBelowPoverty;
    }

    public void setPopulationBelowPoverty(Integer populationBelowPoverty) {
        this.populationBelowPoverty = populationBelowPoverty;
    }

    @Override
    public String toString() {
        return "Governor{"  
                "idGovernor="   idGovernor  
                ", fullName='"   fullName   '\''  
                ", age="   age  
                ", position='"   position   '\''  
                ", dateOfIntercession="   dateOfIntercession  
                ", dateOfResignation="   dateOfResignation  
                ", perCapitaIncome="   perCapitaIncome  
                ", populationBelowPoverty="   populationBelowPoverty  
                '}';
    }
}

NOTE: On your form, you are passing age field as Double, but in your class it's declared as Integer. So you will get exception during deserilization process. Same thing applys for populationBelowPoverty field . Also, your date format is dd/MM/YYYY and I think this is not supported format for jackson. It should be YYYY-MM-dd.

Anyway, if you send a JSON like this:

{
     "idGovernor":1,
     "fullName":"Test",
     "age":1,
     "dateOfIntercession":"2022-06-09",
     "dateOfResignation":"2022-06-17",
     "perCapitaIncome":"123.932",
     "position":"position",
     "populationBelowPoverty":"98"
}

to this controller method:

@PostMapping(value = "/test/governor")
    public Governor testGovernor(@RequestBody Governor governor)  {
        return governor;

    }

You should get response like this :

{
    "idGovernor": 1,
    "fullName": "Test",
    "age": 1,
    "position": "position",
    "dateOfIntercession": "2022-06-09",
    "dateOfResignation": "2022-06-17",
    "perCapitaIncome": {
        "amount": 123.932,
        "zero": false,
        "negative": false,
        "positive": true,
        "amountMajorLong": 123,
        "negativeOrZero": false,
        "amountMinorLong": 12393,
        "amountMinor": 12393,
        "positiveOrZero": true,
        "minorPart": 93,
        "scale": 3,
        "amountMinorInt": 12393,
        "currencyUnit": {
            "code": "USD",
            "numericCode": 840,
            "decimalPlaces": 2,
            "symbol": "$",
            "numeric3Code": "840",
            "countryCodes": [
                "PR",
                "MP",
                "IO",
                "FM",
                "PW",
                "GU",
                "BQ",
                "TC",
                "VG",
                "AS",
                "VI",
                "TL",
                "UM",
                "MH",
                "EC",
                "US"
            ],
            "pseudoCurrency": false
        },
        "currencyScale": false,
        "amountMajorInt": 123,
        "amountMajor": 123
    },
    "populationBelowPoverty": 98
}
  • Related