2

I am writing a rest API. This has to return my object on GET method.

Now, when I request postman, I can get the balanceAmount:120.5. However, my requirement is to return the REST response with the field balanceAmount:121.00. Kind of number formatting and rounding up to the next 50.

Sample input-output:

120.1 => 120.50         
120.9 => 121.00
120   => 120.00

I have to use the amount as double and I cannot make it as a string. The database table has the column type as Numeric(10,2). I am using spring boot 2.6.x and Java 11.

Please suggest an easier way to format such fields.

My POJO is similar to:

class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    @Column(name = "oid", nullable = false, updatable = false)
    private Long oid;
    @Column(name = "balanceAmount", length = 100)
    private Double balanceAmount;
}

Controller:

@RestController
@RequestMapping("/customer")
class CustomerService {    
    @GetMapping("/oid/{oid}")   
    public Customer getCustomer(@PathVariable("oid") String oid) { 
        if (log.isDebugEnabled()) {
            log.debug("oid{} ", oid);
        }
        return new Customer(oid, 120.5);
    }
}
Alexander Ivanchenko
  • 25,667
  • 5
  • 22
  • 46
sandeep kale
  • 321
  • 2
  • 10
  • 1
    Your code relies on some REST framework to perform serialization and parsing to map your Customer class to the bytes actually transmitted over the wire. So if that framework behaves wrongly, consider to help it using a custom serializer/deserializer. How that looks in detail depends on your framework. The only other chance I see is to make the double field transient and introduce a string field that you prepopulate with the desired value. – Queeg Oct 08 '22 at 11:22
  • 1
    1. Hi & Welcome to [so]! 2. I would not "expose db model via web", if i don't had to/just for the quick start...https://stackoverflow.com/q/30549489/592355 – xerx593 Oct 08 '22 at 11:27
  • 1
    (2.) So better to return a `CustomerDto` (on which you can perform transformation(rounding)..a.s.o.) – xerx593 Oct 08 '22 at 11:29
  • @xerx593, Yes agree with your design improvement. Having VO and DTO separate is the safe and correct way. – sandeep kale Oct 13 '22 at 14:02

2 Answers2

1

You obtain a half up ceiling of a double value, you can use standard utility method Math.ceil():

Math.ceil(balanceAmount * 2) / 2

Example:

System.out.println(Math.ceil(120.1 * 2) / 2);
System.out.println(Math.ceil(120.9 * 2) / 2);
System.out.println(Math.ceil(120 * 2) / 2);

Output:

120.5
121.0
120.0

Note: because you can lose precision while performing calculations with doable it highly advisable to BigDecimal to represent prices, taxes, etc. in your domain entities.

Alexander Ivanchenko
  • 25,667
  • 5
  • 22
  • 46
0

Ideally, a value object and data transfer object should not be the same and it may result in the exposure of database structure as suggested by @xerx593. However, my service is already deployed and it's accessed by our services only and not by a public service/application. So, I am not authorized to create a separate DTO for this.

I used a simple JsonDeserializer to solve this issue.

I modified my POJO as: import com.fasterxml.jackson.databind.annotation.JsonSerialize;

class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    @Column(name = "oid", nullable = false, updatable = false)
    private Long oid;

    @Column(name = "balanceAmount", length = 100)
    @JsonSerialize(using = DecimalJsonSerializer.class) //***New Line***
    private Double balanceAmount;
}

And my deserializer class is:

public class DecimalJsonSerializer extends JsonSerializer<Double> {
@Override
    public void serialize(Double value, JsonGenerator jgen, SerializerProvider provider)
            throws IOException {
        jgen.writeNumber(String.format("%.2f", value));
    }
}

I hope this will help someone who wants to display a number, date or other data types in a customized format.

sandeep kale
  • 321
  • 2
  • 10