DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Improving Java Application Reliability with Dynatrace AI Engine
  • A Systematic Approach for Java Software Upgrades
  • Building a Simple RAG Application With Java and Quarkus
  • Dust Actors and Large Language Models: An Application

Trending

  • Using LLMs to Automate Data Cleaning and Transformation Pipelines
  • A Scalable Framework for Enterprise Salesforce Optimization: Turning Outcomes Into an Operating System
  • Bringing Intelligence Closer to the Source: Why Real-Time Processing is the Heart of Edge AI
  • Observability in Spring Boot 4
  1. DZone
  2. Coding
  3. Java
  4. Unit-API: What, How, and Why

Unit-API: What, How, and Why

Learn more about the complexity of using units and the best practices around them, as well as how to build a cloud-portable application.

By 
Otavio Santana user avatar
Otavio Santana
DZone Core CORE ·
Apr. 13, 20 · Tutorial
Likes (2)
Comment
Save
Tweet
Share
11.8K Views

Join the DZone community and get the full member experience.

Join For Free

The now-famous units of measurement are the quantities that determine a substantial amount and that serve as a standard for possible comparisons, and that serves as a standard for other ratios. And just like in the real world, these elements are also used in the world of information technology. However, there several questions: What is the best way to use these standards in software? Are there good practices? What are the impacts of errors? The purpose of this article is to talk a little about the unit of measurement specification in Java.

Many software uses these resources in several points, for example, the weight of a product purchased in e-commerce. However, several questions arise; for example, what is the best way to represent the measured units? After all, why not just use just one numeric type and leave it implicit for your kind? It is impossible to make mistakes, correct? To talk a little about this, we’ll talk about just three examples here:

  1. NASA had an initiative called "Star Wars" in 1983. The Strategic Defense Initiative (SDI) was a proposed missile defense system to protect the United States from attack by strategic ballistic nuclear weapons. The crew of the space shuttle was supposed to position it so that a mirror mounted on its side could reflect a laser beamed from the top of a mountain at 1,023 meters above sea level. The experiment failed because the computer program that controlled the movements of the bus interpreted the information received at the laser site as indicating the elevation in nautical miles instead of feet. As a result, the program positioned the space shuttle to receive lightning from a non-existent mountain, 10,023 nautical miles above sea level. From "The Development of Ballistic Missile Defense Software," by H. Lin, Scientific American, vol. 253, n. 6 (December 1985), p. 51.

  2. NASA's Mars Climate Orbiter crashed in September 1999 because of a "silly mistake": wrong units in a program.

  3. Gimli Glider: Air Canada Flight 143 was a Canadian domestic passenger flight between Montreal and Edmonton that ran out of fuel on July 23, 1983, at an altitude of 41,000 feet, midway through the trip. The reason is another "silly error" of a unit of measures.

For this article not to be a “silly error” software horror story, we will stop here. However, it is worth mentioning that these “silly mistakes” can generate disasters in your business, financial loss, besides that they can cause lives. And the big point is how to use and represent these units of measure in software.

To demonstrate this use, we will create a straightforward travel system, to do something directly and not get out of focus. The article will be a REST application that will manage a trip, with a set of flights, and that trip will have three attributes: the city of origin, city of destination, and the distance.

Here comes the first doubt in modeling, which is the way to represent distance.

Java
 




xxxxxxxxxx
1


 
1
public class Travel {
2
    private String to;
3
    private String from;    
4
    private ? distance;
5
}



The first option will be to represent the type as just a numerical value; for our case, we will try  long .

Java
 




xxxxxxxxxx
1


 
1
public class Travel {   
2
    private String to;
3
    private String from;
4
   private long distance;
5
}



As already mentioned, this approach generates several problems. How do we know which unit of measure the software is using? It could be in meters, kilometers, miles, etc.

A good option, indeed the only international measurement system, is using meters. However, it is not yet explicit, and we will do this by placing the unit of measurement as a suffix.

Java
 




xxxxxxxxxx
1


 
1
public class Travel {    
2
    private String to;
3
    private String from;  
4
    private long distanceMeters;
5
}



Leaving the unit of measure as part of the variable makes it explicit which unit of measure the software is using. However, there is no guarantee that it will be added or converted correctly to your code.

Unit-API

In situations where the type is more complex, there is the classic and famous “When Making a Type” to Martin Followers. A significant advantage of creating the kind is the guarantee and security in the use of its API by the user; that is, we are following the strategy of having a fail-safe API. Previously, I had already written an article talking about the advantages of using an API to type money (I also wrote a very cool book entitled by the community on the same topic). Following the same line of reasoning, we will use the Java specification to work with unit-API measurements.

In the case of this article, a Maven project will be used, so the first step to perform with Unit-API is simply to add the dependency within  pom.xml .

XML
 




xxxxxxxxxx
1


 
1
<dependency>
2
    <groupId>tech.units</groupId>
3
    <artifactId>indriya</artifactId>
4
    <version>2.0.2</version>
5
</dependency>



There is an interesting post that talks about some of the essential resources that exist within the Unit-API. In summary, this API will guarantee your security and stability to handle and manipulate units of measurement without worrying about it since there will be a component that will do that job for you.

Java
 




xxxxxxxxxx
1
22


 
1
import tech.units.indriya.quantity.Quantities;
2
 
          
3
import javax.measure.MetricPrefix;
4
import javax.measure.Quantity;
5
import javax.measure.quantity.Length;
6
 
          
7
import static tech.units.indriya.unit.Units.METRE;
8
 
          
9
public class App {
10
 
          
11
    public static void main(String[] args) {
12
 
          
13
        Quantity<Length> distance = Quantities.getQuantity(1_000, METRE);
14
        Quantity<Length> distanceB = Quantities.getQuantity(54_000, METRE);
15
        final Quantity<Length> result = distance.add(distanceB);
16
        final Quantity<Length> kiloDistance = result.to(MetricPrefix.KILO(METRE));
17
        System.out.println(result);
18
        System.out.println(kiloDistance);
19
 
          
20
    }
21
}
22
 
          



Thus, our distance attribute will be represented by the "Quantity" type of specification. One crucial thing to remember: MongoDB does not support storing this type, so it is necessary that we also create a conversion to save the class in some way. To make it easier, we will store it as "String." Jakarta NoSQL has annotations very similar to JPA since some annotations are agnostic to the persistence of the database.

Java
 




xxxxxxxxxx
1
78


 
1
import jakarta.nosql.mapping.Column;
2
import jakarta.nosql.mapping.Entity;
3
import jakarta.nosql.mapping.Id;
4
 
          
5
import java.time.LocalDate;
6
import java.util.List;
7
 
          
8
@Entity
9
public class Trip {
10
 
          
11
    @Id
12
    private String trip;
13
 
          
14
    @Column
15
    private List<String> friends;
16
 
          
17
    @Column
18
    private LocalDate start;
19
 
          
20
    @Column
21
    private LocalDate end;
22
 
          
23
    @Column
24
    private List<Travel> travels;
25
 
          
26
}
27
 
          
28
 
          
29
import jakarta.nosql.mapping.Column;
30
import jakarta.nosql.mapping.Convert;
31
import jakarta.nosql.mapping.Entity;
32
 
          
33
import javax.measure.Quantity;
34
import javax.measure.quantity.Length;
35
 
          
36
@Entity
37
public class Travel {
38
 
          
39
    @Column
40
    private String to;
41
 
          
42
    @Column
43
    private String from;
44
 
          
45
    @Column
46
    @Convert(LengthConverter.class)
47
    private Quantity<Length> distance;
48
}
49
 
          
50
 
          
51
import jakarta.nosql.mapping.AttributeConverter;
52
 
          
53
import javax.measure.Quantity;
54
import javax.measure.format.QuantityFormat;
55
import javax.measure.quantity.Length;
56
import javax.measure.spi.ServiceProvider;
57
 
          
58
public class LengthConverter implements AttributeConverter<Quantity<Length>, String> {
59
 
          
60
    private static final QuantityFormat FORMAT = ServiceProvider.current().getFormatService().getQuantityFormat();
61
 
          
62
    @Override
63
    public String convertToDatabaseColumn(Quantity<Length> attribute) {
64
        if (attribute == null) {
65
            return null;
66
        }
67
        return FORMAT.format(attribute);
68
    }
69
 
          
70
    @Override
71
    public Quantity<Length> convertToEntityAttribute(String dbData) {
72
        if (dbData == null) {
73
            return null;
74
        }
75
        return (Quantity<Length>) FORMAT.parse(dbData);
76
    }
77
}
78
 
          



In this article, we will use the DTO concept, and a DTO will be created between the entity and the DTO. To find out more details about the DTO trade-off, there is an article that talks about it in a very particular way. The critical point is that I can place some validations with my DTO using Bean Validation.

Java
 




xxxxxxxxxx
1
52


 
1
import javax.validation.constraints.NotBlank;
2
import java.util.List;
3
 
          
4
public class TripDTO {
5
 
          
6
    @NotBlank
7
    private String trip;
8
 
          
9
    private List<String> friends;
10
 
          
11
    @NotBlank
12
    private String start;
13
 
          
14
    @NotBlank
15
    private String end;
16
 
          
17
    private List<TravelDTO> travels;
18
 
          
19
    private int totalDays;
20
 
          
21
    private QuantityDTO distance;
22
}
23
 
          
24
import javax.validation.constraints.NotBlank;
25
import javax.validation.constraints.NotNull;
26
 
          
27
public class TravelDTO {
28
 
          
29
    @NotBlank
30
    private String to;
31
 
          
32
    @NotBlank
33
    private String from;
34
 
          
35
    @NotNull
36
    private QuantityDTO distance;
37
 
          
38
}
39
 
          
40
import javax.validation.constraints.NotBlank;
41
import javax.validation.constraints.NotNull;
42
 
          
43
public class QuantityDTO {
44
 
          
45
    @NotBlank
46
    private String unit;
47
 
          
48
    @NotNull
49
    private Number value;
50
 
          
51
}
52
 
          



The last step of the application is to make resources available thanks to the  TripResource  class. We have the mapper that does the conversion and isolation of the entity in addition to the integration with the database thanks to TripRepository .

Java
 




xxxxxxxxxx
1
81


 
1
import jakarta.nosql.mapping.Repository;
2
 
          
3
import javax.enterprise.context.ApplicationScoped;
4
import java.util.stream.Stream;
5
 
          
6
@ApplicationScoped
7
public interface TripRepository extends Repository<Trip, String> {
8
 
          
9
    Stream<Trip> findAll();
10
}
11
import jakarta.nosql.mapping.Repository;
12
 
          
13
import javax.enterprise.context.ApplicationScoped;
14
import java.util.stream.Stream;
15
 
          
16
@ApplicationScoped
17
public interface TripRepository extends Repository<Trip, String> {
18
 
          
19
    Stream<Trip> findAll();
20
}
21
 
          
22
import org.modelmapper.ModelMapper;
23
 
          
24
import javax.enterprise.context.ApplicationScoped;
25
import javax.inject.Inject;
26
import javax.validation.Valid;
27
import javax.ws.rs.Consumes;
28
import javax.ws.rs.DELETE;
29
import javax.ws.rs.GET;
30
import javax.ws.rs.POST;
31
import javax.ws.rs.Path;
32
import javax.ws.rs.PathParam;
33
import javax.ws.rs.Produces;
34
import javax.ws.rs.WebApplicationException;
35
import javax.ws.rs.core.MediaType;
36
import javax.ws.rs.core.Response;
37
import java.util.List;
38
import java.util.stream.Collectors;
39
 
          
40
@Path("trips")
41
@Consumes(MediaType.APPLICATION_JSON)
42
@Produces(MediaType.APPLICATION_JSON)
43
@ApplicationScoped
44
public class TripResource {
45
 
          
46
    @Inject
47
    private TripRepository repository;
48
 
          
49
    @Inject
50
    private ModelMapper mapper;
51
 
          
52
    @GET
53
    public List<TripDTO> findAll() {
54
        return repository.findAll()
55
                .map(t -> mapper.map(t, TripDTO.class))
56
                .collect(Collectors.toList());
57
    }
58
 
          
59
    @GET
60
    @Path("{id}")
61
    public TripDTO findById(@PathParam("id") String id) {
62
        return repository.findById(id)
63
                .map(d -> mapper.map(d, TripDTO.class))
64
                .orElseThrow(
65
                        () -> new WebApplicationException(Response.Status.NOT_FOUND));
66
    }
67
 
          
68
    @POST
69
    public TripDTO insert(@Valid TripDTO tripDTO) {
70
        final Trip trip = mapper.map(tripDTO, Trip.class);
71
        return mapper.map(repository.save(trip), TripDTO.class);
72
    }
73
 
          
74
    @DELETE
75
    @Path("{id}")
76
    public void deleteById(@PathParam("id") String id) {
77
        repository.deleteById(id);
78
    }
79
 
          
80
}
81
 
          



Within the entity we have two methods for reading: one to return the total distance and the total of days used on that trip.

Java
 




xxxxxxxxxx
1
19


 
1
@Entity
2
public class Trip {
3
 
          
4
// more code ....
5
 
          
6
    public Quantity<Length> getDistance() {
7
        return getTravels()
8
                .stream()
9
                .map(Travel::getDistance)
10
                .reduce((a, b) -> a.add(b))
11
                .orElse(Quantities.getQuantity(0, Units.METRE));
12
    }
13
 
          
14
    public long getTotalDays() {
15
        return ChronoUnit.DAYS.between(start, end);
16
    }
17
 
          
18
}
19
 
          



And it is possible to create units of measures based on the distance SI, in this case, the mile:

Java
 




xxxxxxxxxx
1


 
1
Unit<Length> mile = Units.METRE.multiply(1609.344).asType(Length.class);



And it is possible to use and handle it safely without the small errors, and significant disasters mentioned at the beginning of the article.

Once the application is ready, the next step is to upload the app and perform the tests.

Shell
 




xxxxxxxxxx
1


 
1
 mvn clean package kumuluzee:repackage
2
 java -jar target/microprofile.jar



The application is up and running, so the next step is to enter data and check the result:

Shell
 




xxxxxxxxxx
1


 
1
curl --location --request POST 'http://localhost:8080/trips' \
2
--header 'Content-Type: application/json' \
3
--header 'Content-Type: application/json' \
4
--data-raw '{"trip": "euro-trip", "friends": ["Otavio", "Edson", "Bruno"], "start": "2010-03-01", "end": "2010-04-01", "travels": [
5
{"to": "London", "from": "São Paulo", "distance": {"unit": "km", "value": 9496.92}}, {"to": "London", "from": "Paris", "distance": {"unit": "km", "value": 342.74}}, 
6
{"to": "Paris", "from": "Rome", "distance": {"unit": "km", "value": 1106.27}}]}'
7
curl 'http://localhost:8080/trips'


Move to The Cloud

Recently the term cloud-native has become quite popular and much-discussed, describing a set of best practices for optimizing an application in the cloud through the container, orchestration, and automation.

A straightforward way to take your application cloud-native is through Platform.sh. In general, it is a platform as a service, PaaS, which is committed to the concept of infrastructure as code.As mentioned in this article, at least three files are required to perform the deployment: One for application, for services, and another for routes.


YAML
 




xxxxxxxxxx
1


 
1
mongodb:
2
  type: mongodb:3.6
3
  disk: 1024
4
 
          



In this article, we talked a little about the unit of measures, the motivation to use good practices like using type when the variable requires a high degree of complexity like the units of standards, in addition to creating an application that is easily portable to the cloud. Thanks to Java technologies that are mature and are increasingly prepared for the world of cloud-native.

application Java (programming language)

Opinions expressed by DZone contributors are their own.

Related

  • Improving Java Application Reliability with Dynatrace AI Engine
  • A Systematic Approach for Java Software Upgrades
  • Building a Simple RAG Application With Java and Quarkus
  • Dust Actors and Large Language Models: An Application

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook