Handle measures and their unit with javax.measure - wk-tw/prez-tech-201106 GitHub Wiki

Units of Measurement

Dependencies

implementation("javax.measure:unit-api:2.0")
implementation("tec.units:unit-ri:1.0.3")

javax.measure.Quantity

Definition

public interface Quantity<Q extends Quantity<Q>>

Note: Recursion

Example:

data class User(
    val id: String,
    val firstName: String,
    val lastName: String,
    val dateOfBirth: LocalDate,
    val size: Quantity<Length>,
    val weight: Quantity<Mass>
)

Unit

Units from tec.units.ri.unit.Units

public static final Unit<Power> WATT = addUnit(new AlternateUnit<Power>(JOULE.divide(SECOND), "W"), Power.class);
public interface Unit<Q extends Quantity<Q>>
public interface Power extends Quantity<Power>

Create Instance

Use method getQuantity

public static <Q extends Quantity<Q>> Quantity<Q> getQuantity(Number value, Unit<Q> unit)

Example:

tec.units.ri.quantity.Quantities

val weight = Quantities.getQuantity(300, Units.KILOGRAM)

Serialization & Deserialization

Does not implement Serializable

@Test
fun serialize() {
    Quantities.getQuantity(300, Units.KILOGRAM)
        .let(jacksonObjectMapper()::writeValueAsString)
        .also(System.out::println)
}
com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) ...

    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:770)
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178)
    at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:119)
    at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:79)
    ...

Must implement custom Jackson serializer and deserializer

@Test
fun serialize() {
    Quantities.getQuantity(300, Units.KILOGRAM)
        .let(mapper::writeValueAsString)
        .also(System.out::println)
}
{"value":300.0,"unit":"kg"}

Create custom unit

Create new unit

val HORSE_POWER = Units.WATT.multiply(756.7)

Add it into SimpleUnitFormat for parsing

SimpleUnitFormat.getInstance().label(HORSE_POWER, "hp")

Example:

@Test
fun customUnit() {
    Quantities.getQuantity(300, CustomUnits.HORSE_POWER)
        .let(mapper::writeValueAsString)
        .also(System.out::println)
}
{"value":300.0,"unit":"hp"}
@Test
fun customUnit() {
    val WANG = Units.WATT.multiply(Units.METRE).divide(Units.DAY)
    val quantity = Quantities.getQuantity(300, WANG)
    quantity.also(System.out::println)
    SimpleUnitFormat.getInstance().label(WANG, "WG")
    quantity.also(System.out::println)
}
300 W·m/day
300 WG

Prefix

Use prefix MetricPrefix for further units

@Test
fun serialize() {
    Quantities.getQuantity(100, MetricPrefix.CENTI(Units.METRE))
        .let(mapper::writeValueAsString)
        .also(System.out::println)
}
{"value":100.0,"unit":"cm"}

Conversion

Quantity<Q> to(Unit<Q> unit)

Example:

@Test
fun convertUnit() {
    Quantities.getQuantity(100, CustomUnits.HORSE_POWER)
        .to(Units.WATT)
        .let(mapper::writeValueAsString)
        .also(System.out::println)
}
{"value":75670.0,"unit":"W"}

Other libraries

Also from Units of Measurement

implementation("systems.uom:systems-unicode:2.0.2")
implementation("systems.uom:systems-quantity:2.0.2")
implementation("systems.uom:systems-common:2.0.2")

Example:

tech.units.indriya.quantity.Quantities

@Test
fun `from systems uom`() {
    Quantities.getQuantity(1, CLDR.FOOT)
        .to(CLDR.METER)
        .also(System.out::println)
}
0.3048 m

Locale-specific formatting [open issue]

⚠️ **GitHub.com Fallback** ⚠️