{{announcement.body}}
{{announcement.title}}

Unit-API: What, How, and Why

DZone 's Guide to

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.

· Java Zone ·
Free Resource

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
 







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

Java
 







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
 







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
 







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
 







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
 







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







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.

Topics:
cloud ,java ,jnosql ,paas ,paas cloud

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}