Search code examples
javaspringbigdecimal

Receiving "Not a valid char constructor input" error when passing decimals


I am receiving "Not a valid char constructor input" when passing decimal. My code is below. I have researched and found that by changing from BigDecimal to Formatdeciaml solves the problem, but I can't do that because then my mapper needs to be changed as well. Any help would be appreciated!!

Controller

  String postagePaid = (String) request.getParameter("tPostagePaid");
                String insuranceFees = (String) request.getParameter("tInsuranceFees");
                String registeredFees = (String) request.getParameter("tRegisteredFees");
                String codFees = (String) request.getParameter("tCODFees");
                String insRegisteredCODFees = (String) request.getParameter("tInsuranceFees");
                System.out.println("insurance Fee: " + insuranceFees);
                if (postagePaid != null && !insuranceFees.isEmpty()) { // postage paid amount
                    claim.setClPostagePaidAmt(new BigDecimal(postagePaid));
                }
                if (insuranceFees != null && !insuranceFees.isEmpty()) { // Insurance Fees
                    claim.setClInsuranceFee(new BigDecimal(insuranceFees));
                }
                if (registeredFees != null && !insuranceFees.isEmpty()) { // Registered Fees
                    claim.setClRegisteredFee(new BigDecimal(registeredFees));
                }
                if (codFees != null && !insuranceFees.isEmpty()) { // COD Fees
                    claim.setClCodFee(new BigDecimal(codFees));
                }
                claim.setClInsRegCodAmt(null);

Error:

Caused by: java.lang.NumberFormatException: Not a valid char constructor input: 
at java.math.BigDecimal.bad(BigDecimal.java:1859)
at java.math.BigDecimal.charParser(BigDecimal.java:1303)
at java.math.BigDecimal.<init>(BigDecimal.java:922)
at java.math.BigDecimal.<init>(BigDecimal.java:901)
at   gov.usps.oic.controller.OicClaimEntryControlloer.submitClaim(OicClaimEntryControlloer.java:991)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:60)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
at java.lang.reflect.Method.invoke(Method.java:611)
at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:745)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:686)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:953)

Solution

  • Based on your comments this question is ultimately about taking unknown input and parsing it into a BigDecimal. You can use regular expressions to get the number values out of a String.

    public class Program {  
        private static Object lock = new Object();
        private static final Pattern BIG_DECIMAL_MATCHER;
    
        static {
            synchronized (lock) {
                BIG_DECIMAL_MATCHER = Pattern.compile("-?(?:\\d+(?:\\.\\d+)?|\\.\\d+)"); 
                // credit to stackoverflow.com/questions/14343551
            }
        }
    
        /**
         * Attempts to force a given String value to a valid BigDecimal. If there are 
         * multiple valid BigDecimal values, only the first is returned.
         */
        static BigDecimal forceBigDecimal(String value) { 
            Matcher moneyMatcher = BIG_DECIMAL_MATCHER.matcher(value);
    
            while (moneyMatcher.find()) {
                return new BigDecimal(moneyMatcher.group());
            }
            throw new NumberFormatException(
                String.format("Valid number not found in value: %s", value));
        }
    }
    

    Example usage:

    List<String> moneyValues = new ArrayList<String>() {{
        add("$42.35"); add("Fee: $10.25"); add("฿1200");
        add("obviously not valid input"); 
        add("not too 42 sure . 12about this one"); 
        add("or this $..3"); 
        add("$42.35 $84.50");
    }};
    
    for (String value : moneyValues) {
        try {   
            BigDecimal parsed = Program.forceBigDecimal(value); 
            System.out.println(parsed);
        } catch (NumberFormatException ex) { 
            ex.printStackTrace();
            continue;
        }
    }
    

    Outputs:

    42.35
    10.25
    1200
    java.lang.NumberFormatException: Valid number not found in value: obviously not valid input
        at soj25597001.Program.forceBigDecimal(Program.java:50)
        at soj25597001.Program.main(Program.java:22)
    42
    0.3
    42.35