My opinion on talks from JPoint Moscow 2019

Reading Time: 4 minutes

If you have read my previous parts, this is the last one in which I will give my highlights on the talks that I have visited.

First stop was the opening talk from Anton Keks on topic The world needs full-stack craftsmen. Interesting presentation about current problems in software development like splitting development roles and what is the real result of that. Another topic was about agile methodology and is it really helping the development teams to build a better product. Also, some words about startup companies and usual problems. In general, excellent presentation.

Simon Ritter, in my opinion, he had the best talks about JPoint. First day with the topic JDK 12: Pitfalls for the unwary. In this session, he covered the impact of application migration from previous versions of Java to the last one, from aspects like Java language syntax, class libraries and JVM options. Another interesting thing was how to choose which versions of Java to use in production. Well balanced presentation with real problems and solutions.

Next stop Kohsuke Kawaguchi, creator of Jenkins, with the topic Pushing a big project forward: the Jenkins story. It was like a story from a management perspective, about new projects that are coming up and what the demands of the business are. To be honest, it was a little bit boring for me, because I was expecting superpowers coming to Jenkins, but he changed the topic to this management story.

Sebastian Daschner from IBM, his topic was Bulletproof Java Enterprise applications. This session covered which non-functional requirements we need to be aware of to build stable and resilient applications. Interesting examples of different resiliency approaches, such as circuit breakers, bulkheads, or backpressure, in action. In the end, adding telemetry to our application and enhancing our microservice with monitoring, tracing, or logging in a minimalistic way.

Again, Simon Ritter, this time, with the topic Local variable type inference. His talk was about using var and let the compiler define the type of the variable. There were a lot of examples, when it makes sense to use it, but also when you should not. In my opinion, a very useful presentation.

Rafael Winterhalter talked about Java agents, to be more specific he covered the Byte Buddy library, and how to program Java agents with no knowledge of Java bytecode. Another thing was showing how Java classes can be used as templates for implementing highly performant code changes, that avoid solutions like AspectJ or Javassist and still performing better than agents implemented in low-level libraries.

To summarize, the conference was excellent, any Java developer would be happy to be here, so put JPoint on your roadmap for sure. Stay tuned for my next conference, thanks for reading, THE END 🙂

Impressions from UIKonf Berlin 2019

Reading Time: 5 minutes

With little doubts in the beginning, big uncertainty and the questions in my head “Is this the right conference?”, “Should I’ve chosen another conference?”… But it happened and I’m satisfied at the end of the day with my choice. Some of my colleagues were surprised of my choice (Berlin), but yes, I can definetly say “It was not a mistake”.

So how was it?

Day 1: Social events

I’ve chosen to be with the walking tour group. There were possibilities to be in different groups like Bicycle group, Boat trip group… But this was my choice. We were split into two groups by 12 people and a local tour guide. We visited different spots, like the Memorial to the Murdered Jews of Europe, the popular Checkpoint Charlie, the Berlin French Cathedral, the Brandenburg Gate, etc…

The day finished in a big restaurant where we received our conference badges and promo materials of the conference. It was a very relaxed atmosphere and new chance to meet and introduce yourself to new developers. Some of the participants were professionally oriented and immediately started to talk about iOS topics. Some were on their way to the bar ordering german beers and the popular “wursts”. There also was a small group that played some kind of table tennis game. I’ve attended in all of these social activities.

Day 2: Opening day of the UIKonf 2019

After the opening words and the short introduction, the conference officially started. The first day consisted of 9 presentations. The strongest impression of the day was the presentation of Ellie Shin about Mock Generator for Swift and how they at Uber solved the problem of mocking. They optimized the app to build the mocks in around 10 seconds instead of the previous time needed; it was more than 1 hour.

One of the best presentations of the day was from the lovely Julietta Yaunches. She talked about consistency principles in programming, how to keep the coding style consistent and not make big changes every day, how to decide when to introduce something new in your code, etc.

It were good presentations from Kristina Fox about Internationalization of the iOS applications, and the opening presentation from Kaya Tomas about Accessibility and Inclusion in the apps. A topic I wasn’t aware before this conference.

I also have to mention the presentation of Glenna Buford about how to organize the network stack of your iOS application.

The day finished with a social event named Ambassador’s dinner. The local participants of the conference had the task to show the other participants (foreigners, including me) the typical restaurants and bars in Berlin. I was in a group that visited Hofbrau Munich Restaurant in Berlin. We had some good discussions with colleagues from all over the World. Throughout the evening we enojyed some tasty good german beer and pork meat.

Day 3: 2nd day of UIKonf 2019

The second day had 9 new presentations and 9 new speakers.

The best of the day in my opinion was the presentation of Kate Castellano. She talked about applications with backend driven UI.

Among the better presentations was of Neha Kulkarni about Advanced Colors in Swift.

I will also mention Erica Sadun. She talked about Swift Strings. In her presentation she showed best practices about using strings in Swift, interpolation of strings, etc.

Also there was a choice to visit 2 workshops on MyTaxi boat stage near the conference hall. I visited this stage and it was about the management process, recruiting and organizing the teams in MyTaxi company. The 2nd presentation was about Tips and Tricks they are using for testing their apps.

The day finished with a big party in a local restaurant near the river Spree. It was another good party. A lot of talks with colleagues, a lot of drinks, good atmosphere. All finished at 1:00 am.

Recap

I can freely say it was a good conference, perfectly organized… I didn’t regret in any moment that I’ve chosen this one in a bunch of other conferences. First of all, I’ve learned a lot of new things, I’ve heard about topics I wasn’t aware before, I saw how it would be to talk infront of 500 people.

Maybe in these events the most important thing is the social component. New faces, positive people, talks, sharing experiences, enlarge your professional contact list.

All 18 speakers

I’m not sure what was the intention of the organizers to have only women speakers. 18 speakers – 18 women. It was not explained, but we cannot complain because the speakers dealt with the challenge perfectly.

Worth the money, worth spending my time at UIKonf in Berlin. I have a feeling I will visit it for sure again in the future.

Java 8 Streams

Reading Time: 5 minutes

Java Stream API was added in Java 8 in order to provide a functional approach to process a collection of objects. Do not get confused with I/O Streams, Java 8 Streams are a completely different thing.

Java Stream does not store data and is not a data structure. Also the underlying data source is not modified.

Java Stream uses functional interfaces and supports functional-style operations on streams of elements using lambda expressions.

Stream operations

Stream operations are divided into intermediate and terminal operations.

Intermediate operations are Stream operations that return a new Stream. These operations are used for producing new stream elements and to send the stream to the next operation. These operations are lazy, i.e. they are not executed until the result of the processing is needed.

List of all Stream intermediate operations:

  • filter()
  • map()
  • flatMap()
  • distinct()
  • sorted()
  • peek()
  • limit()
  • skip()

Terminal operations are Stream operations that do not return a new Stream. Once the terminal method is called in a stream, it consumes the stream and after that the stream can not be used anymore. Terminal operations are processing all the elements in the stream before they return the result.

List of all Stream terminal operations:

  • toArray()
  • collect()
  • count()
  • reduce()
  • forEach()
  • forEachOrdered()
  • min()
  • max()
  • anyMatch()
  • allMatch()
  • noneMatch()
  • findAny()
  • findFirst()

Some code examples

forEach

The simplest and most common operation, it loops over the elements of the stream, calling the supplied code on each element.

Map<Integer, List<User>> usersByAge = users.stream().collect(Collectors.groupingBy(User::getAge));  
usersByAge.forEach((age, u) -> System.out.format("age %s: %s\n", age, u)); 
// age 18: [John]   
// age 23: [Alex, David]   
// age 12: [Peter]

map

Produces new stream after applying a function to each element of the existing stream. It can produce a new stream of different type.

Integer[] userIds= { 5, 2, 7 }; 
List<User> users= Stream.of(userIds).map(employeeRepository::findById) 
.collect(Collectors.toList());   
assertEquals(users.size(), userIds.length);

collect

Repacks element to new data structure on data elements from the existing stream.

List<Employee> users= usersList.stream().collect(Collectors.toList()); 
assertEquals(usersList, users); 

filter

Produces new stream that contains elements from the existing stream that are fulfilling some criteria from the predicate.

users.stream().filter(user -> user.getAge() > 20) 
.collect().collect(Collectors.toList());

findFirst

Returns an Optional for the first entry in the stream.

users.stream().filter(user -> user.getAge() > 20).findFirst().orElse(null);

findAny()

Returns an Optional from any entry in the stream. It will most likely return the first entry in the stream in a non-parallel execution, but there is no guarantee for that.

users.stream().filter(user -> user.getAge() > 20).findAny().orElse(null);

toArray

Returns array from the stream.

User[] users = usersList.stream().toArray(User[]::new); 
assertThat(usersList.toArray(), equalTo(users));

flatMap

Used to flatten the data structure to simplify further operations on the stream. Useful for complex data structures.

List<String> names1 = Arrays.asList(“Peter”, “David”); 
List<String> names2 = Arrays.asList(“Dave”, “Robert”);  
List<String> names3 = Arrays.asList(“Tom”, “Tim”);  
List<List<String>> names = Arrays.asList(names1, names2, names3);  
List<String> flatNames = names.stream().flatMap(Collection::stream).collect(Colectors.toList());

peek

Performs the specified operation on each element of the stream and returns a new stream that can be used for further processing.

User[] arrayOfUsers = {  
new User(1, "James", 100000.0), 
new User(2, "Martin", 200000.0), 
new User(3, "David", 300000.0) }; 
List<User> userList = Arrays.asList(arrayOfUsers);  
userList .stream() 
.peek(e -> e.salaryIncrement(10.0))
.peek(System.out::println) 
.collect(Collectors.toList());   
assertThat(userList, contains(
hasProperty("salary", equalTo(110000.0)),  
hasProperty("salary", equalTo(220000.0)), 
hasProperty("salary", equalTo(330000.0))   
));

sorted()

Sorted is an intermediate operation which returns a sorted view of the stream. The elements are sorted in natural order unless you pass a custom Comparator.

List<String> names = Arrays.asList("Peter", "Dave", "Mike", "David", "Pete"); 
names.stream().sorted().map(String::toUpperCase).forEach(System.out::println);  
Output:
DAVE
DAVID
MIKE
PETE
PETER

Keep in mind that sorted does only create a sorted view of the stream without manipulating the ordering of the backed collection. The ordering of names is untouched.

count()

Count is a terminal operation returning the number of elements in the stream as a long.

long total = names.stream().filter((s) -> s.startsWith("D")).count(); 
System.out.println(total);  
Output: 2

reduce()

This terminal operation performs a reduction on the elements of the stream with the given function. The result is an Optional holding the reduced value.

List<Car> cars  = Arrays.asList(new Car("Kia", 19500), 
new Car("Hyundai", 20500),  
new Car("Ford", 25000),  
new Car("Dacia", 20000)); 

Optional<Car> car = cars.stream().reduce((c1, c2) 
-> c1.getPrice() > c2.getPrice() ? c1 : c2);  
car.ifPresent(System.out::println);  
Output: Ford 25000 

anyMatch()

The method accepts Predicate as an argument. This will return true once a condition passed as predicate satisfy. It will not process any more elements.

List<String> names = Arrays.asList("Peter", "Dave", "Mike", "David", "Pete"); 
boolean matched = names.stream().anyMatch(name -> name.startsWith("D"));  
System.out.println(matched);  
Output: true

allMatch()

The method accepts Predicate as an argument. The Predicateis applied to each entry in the stream and if every element satisfies the passed Predicate, then it returns true otherwise false.

List<String> names = Arrays.asList("Peter", "Dave", "Mike", "David", "Pete"); 
boolean matched = names.stream().allMatch(name -> name.startsWith("D")); 
System.out.println(matched);   
Output: false

noneMatch()

The method accepts Predicate as an argument. The Predicate is applied to each entry in the stream and if every element does not satisfy the passed Predicate, then it returns true otherwise false.

List<String> names = Arrays.asList("Peter", "Dave", "Mike", "David", "Pete"); 
boolean matched = names.stream().noneMatch(name -> name.startsWith("S"));
System.out.println(matched); 
Output: true

Conclusion

In this article we showed some of the details of the new Stream API in Java 8. We saw various operations and how lambdas are used to reduce a huge amount of boilerplate code.


Unit testing using JSONassert library

Reading Time: 3 minutes

In this article, we’ll have a closer look at a library called JSONassert library. We will explain using some examples and how this library can be used. So, let’s get started!

Working with an easy example:

Let’s start our tests with a simple JSON string comparison:

String actual = "{objectId:123, name:\"magy\",lastName:\"henry\"}"; String expected="{objectId:123,name:\"magy\"}"; JSONAssert.assertEquals(expected, actual, false);

The above example will work for the condition strict=false. However, if it is set to true, the test will fail. You have to keep in mind, that JSONAssert makes a logical comparison of the data. This means that the ordering of elements does not matter while dealing with JSON objects.

Working with a complex example

Assuming, that you want a unit test where you have to validate (match an actual response with expected) our rest interfaces in the JUnit. Our endpoint delivers a list of objects. So, the goals are to verify the properties of each object. Let’s assume that delivered response is a list of a type called partner, where the implementation of the class partner is as following:

@Data
public class Partner {
    private String id;
    private String firstName;
    private String lastName;
    private LocalDate birthDate;
    private Gender gender;
    private MaritalStatus maritalStatus;
    private String phoneNumber;
}

The following Java examples will help you to understand the usage of. Assuming, we need to write some assertions for each family member on the list. So, the following should be done.

ResponseEntity<List<Partner>> response = restTemplate.exchange(
  "http://localhost:8080/partners/x/family",
  HttpMethod.GET,
  null,
  new ParameterizedTypeReference<List<Partner>>(){});
List<Parnter> partners= response.getBody();
//Now we need to test that each partner in the family has a certain values. 
Parnter partner1= partners.stream.filter(partner -> parnter.getid().equals("1")).findFirst().get();
assertEquals("Magy", partner1.getFirstName());
assertEquals("Mueller", partner1.getLastName());
assertEquals(of(1980, 7, 12), partner1.getBirthDate());
assertEquals(FEMALE, partner1.getGender());
assertNull(partner1.getMaritalStatus());

// Testing the second person
Parnter partner2= partners.stream.filter(partner -> parnter.getid().equals("2")).findFirst().get();
assertEquals("Marc", partner2.getFirstName());
assertEquals("Ullenstein", partner2.getLastName());
assertEquals(of(1988, 7, 13), partner2.getBirthDate());
assertEquals(MALE, partner2.getGender());
assertNull(partner1.getMaritalStatus());

So, to test the values for just one partner, it takes some time. So, in case of testing multiple partners, it will take a lot of code lines. We would like to use JSONAssert. To make it easier using JSONAssert, let’s create a JSON file under test/resources/json in which we create a list of objects, where each object contains the properties, that will be tested. You should also have in mind, that this library allows developers not having a restrict mode, which means that you don’t have to test against each property.

String actual= restTemplate.getForObject("http://localhost:8080/partners/x/family", String.class);
String expected = IOUtils.toString(this.getClass().getResourceAsStream("/json/expectedJsonResponse.json"),"UTF-8");
JSONAssert.assertEquals(expected, actual, false);

The above method takes three parameters as seen in the above example, where the first parameter is the expected JSON. The second one is the result, or what we got as a response from our endpoint. The third one defines whether we should use the strict mode or not. When comparing the code written in both cases, you are going to think about why you should use this library in future. You can give up all of the used assertions in the above example.

Conclusion

In this article, we looked at multiple scenarios in which JSONAssert can be helpful. We started with a very simple example and moved on to more complex comparisons. And, as always, stay tuned for new interesting articles.

Was there something good in waterfall that lacks in agile – DDD

Reading Time: 9 minutes

There is just one part, one piece step/phase of both methodologies agile and waterfall in which the old fashion way, thinking of one aspect, has some advantage over the new one agile. This does not have to mean that agile (scrum) is bad and developing projects by this methodology are doomed to fail and all other projects managed by waterfall will have great success. The idea of this blog will be to motivate managers and others to think a little bit more out of the box, instead of blindly implementing and using everything from the books what is new. Before we start to talk about whether something is missing or not in agile let’s first introduce basics of both methodologies.

Agile way

These days every software developer knows the basics of agile which are given in the agile manifesto:

We are uncovering better ways of developing software by doing it and helping others do it. Through this work we have come to value:


Individuals and interactions over processes and tools
Working software over comprehensive documentation
Customer collaboration over contract negotiation
Responding to change over following a plan


That is, while there is value in the items on the right, we value the items on the left more.

https://agilemanifesto.org/

These thoughts are maybe more abstract, but looking more from real life experience we can define twelve principles:

  1. Customer satisfaction by early and continuous delivery of valuable software
  2. Welcome changing requirements, even late in development
  3. Deliver working software frequently (weeks rather than months)
  4. Close, daily cooperation between business people and developers
  5. Projects are built around motivated individuals, who should be trusted
  6. Face-to-face conversation is the best form of communication (co-location)
  7. Working software is the primary measure of progress
  8. Sustainable development, able to maintain a constant pace
  9. Continuous attention to technical excellence and good design
  10. Simplicity—the art of maximizing the amount of work not done—is essential
  11. Best architectures, requirements, and designs emerge from self-organizing teams
  12. Regularly, the team reflects on how to become more effective and adjusts accordingly

This is a theory what should some agile methodology have. And again there are no strict phases that one project has to go through during its lifecycle.

The most used methodology that is based on agile is scrum, so we are going to talk about it. It is a methodology which implements the principles of agile. Because it is a real practical process of developing some software it has strictly defined processes of how the software should be developed.

The project should be done in a series of iterative small steps which are called sprints. One sprint should have a maximum period of one month. Most common is two weeks. Following pictures shows how scrum phases and sprints look like:

What can we focus on from all of this? The main goal in Scrum – Agile is to develop incrementally. Always split all requirements on smaller ones and work on a few of them every sprint. The idea is to make small requirements so that several can fit and can be done in one sprint. After every sprint, there will be a release and will be presented to the PO for review (features bugs etc).

Waterfall way

Many of the older generations may have been working on some projects organized in this way and they know and are familiar with the main differences compared with agile. But for all others, we will try to explain it in few words.

Basic model flow for the waterfall has following stages:

  1. Software Requirements
  2. Analysis
  3. System Design
  4. Coding and Implementation
  5. Testing and Verification
  6. Operation and Maintenance

And we can see few diagrams and models how waterfall looks like:

Here we can see that nothing is repeatable and everything is strictly defined. When the project starts, it has to go through every stage and every stage has to be confirmed that is correctly done. But what means no repeatable. It means that in all of these phases should be covered all scenarios that have to be implemented and are planned for the project.

Or more detailed explanation, when the analysing of the requirements starts, it will be for all requirements that should be in the project. It can take maybe one month or more. It can not be done with just a few meetings between the clients and business analysts, because in this phase all requirements should be defined in detail.

After both sides agree that requirements/business scenarios defined in these stages are good and are everything that will be done, the next stage, the design will start. In some ways, this is the stage when real implementation starts. Architects and designers are analysing all the requirements, written in the first stage, and with that information and knowledge, they will start to design the model and set up the application (technologies and frameworks which will be used).

Next step will be implementing all requirements. The process with development and testing of every requirement after it is done. In the same phase, bugs will be fixed along with everything else.

After all requirements are done and tested, the project goes in the final phase which will be the deadline when the project has to go live – production.

Right way of implementing Agile

Comparing these two ways of managing/doing one project we can agree that agile is much better and more reliable to be used instead of waterfall. We don’t have to wait a long period to be sure that we are doing what is right and if it will be accepted from the clients. Acceptance of the project is with every iteration.

Why is this more and more adopted from companies that develop different applications, small and big? It is because they can be sure that everything that they are going to do this month will be accepted. If it is not they are going to lose the effort only for that month. Not the effort and work for one year like in waterfall.

Starting from this point companies are forcing to have something from the start. Don’t like to spend time on analyzing and defining the whole data domain, taking in advance all requirements and setting up the whole architecture by the real needs of the project. That will cost them time and money.

Everything will start great. All stories, epics will be defined after the projects start. Split them in small requirements which can be done during one sprint, they will be defined during the sprints or few sprints before they have to be done. There will be no useless work and effort.

The data model will be defined and created with every new requirement, with every new feature or maybe some bug. At the beginning that data model will serve very well. Requirements can be done fast because there will be no issue of creating a new entity and reference it to some existing one. DDD will be fulfilled while we solve every ticket. First, define the data then implement the code.

But this will be done only for the small parts of the data model and of the project. There will be no defining big data domain that will be useful for the features that will come next. For a week, month or year.

After some time and set up some data model, with every new ticket that will require model changing we will have more and more difficulties to adapt existing data model for the new requirements. In one moment we will have to do bigger changes in the model. The main reason for this is that when we implemented the requirements we cared only for the needs that we had in the sprint when we worked on the previous ticket, story etc and we were not aware of the needs of the model for the featured requirements.

Then we will have let’s say two solutions:

  • To continue to try to work on the model that we made it by now. Which will make implementing our new changes harder, and with that more time-consuming.
  • Or at one moment stop with new features and spend time on a big refactor of the data model. Which will take a long time without doing anything productive on the project with new features, just refactoring.

In both scenarios we will have less productivity then we had before and less than we expected.

If we make a retrospective what we have done, we will see that we save time at the beginning on analyzing and defining the whole data model but after some time, year or more, we will spend the same or maybe more time on dealing with the bad data model or big data refactoring.

These possible issues that we can have in future, with forcing fully agile from the very start, can be easily avoided if we add one more phase before implementing requirements. Just spend time on analyzing, defining and modelling of the main big crucial epic stories that we have to cover with our project. Which is more like DDD in the waterfall methodology.

47N Playground: Be up-to-date with the latest technologies and don’t waste resources

Reading Time: 4 minutes

Our company is established from techies 👨🏼‍💻 for techies 👩🏼‍💻 and therefore we love ♥️ technology. This passion brings us always forward 🏃🏿‍♂️to learn the latesst technologies and keeps us hungry for solving also our own issues with some cool 😎 and fun-making technologies 🤩.

To be an attractive technology focussed employer

A simple agency lifestyle with working on preselected technologies from clients for a long period can (and will) be boring 😕 for every technology enthusiast. 🧝‍♂️ To keep everybody on a high level of motivation 💪🏻, we think a company has to develop his own spirit and in our case, these are solutions with the latest frameworks, technologies, languages, gadgets,…

How not to waste time and money?

But in agency life is hard to reserve some resources 💰 just for a playground 🎮 or disposable products. Therefore you will need a setup, where you transform the need for discovering 🔍 new areas and costs 💰 into an intelligent investigation 🤑. By this frame, we decided, that every outcome of our playground should result as a standalone solution either for our company or as a resealable product. By doing this, our new unit LABS 🧪 and researchers 👩🏼‍🔬👨🏻‍🔬 are born.

How our unit LABS are working?

First steps into new area!

In LABS 🧪 we get in the first touch with latest technologies and for sure we will face with all the issues ☄️, problems 👮🏻‍♂️, bugs 🐞, challenges 👨🏼‍🎤 and we learn a lot about the bad sides of new technologies. If we overcome all this problems and troubles 🧗🏿‍♂️, we move this new technology from our #playground to #weStandFor, which means that we are that good in that new technology and faced and solved all issues, that can occur. Now we are ready and stand for the latests technologies! 🏆🥇
Thus, the outcome of an e.g. 3 months focus in LABS is a great knowledge about a brand new technology and a gorgeous new product or solution. I think we can be proud of both! 👏🏻👏🏻

The movement of technology from #playground to #weStandFor. Every stack has his own topic leader, so don’t miss changes and updates.

To manage this pipeline from playground 🎮 to the output ✅ we set up a backlog with great projects. Everybody in our company is free to add some projects to our backlog and come up with ideas 💡. In this accelerator program, we decide the sustainability and the potential of this suggested project 📊 and evaluate the sexiness of the technologies 🙀. If we all agree with this internal pitch we plan and start having work and fun! 🥳

What does this mean for our partners and clients?

With our LABS unit, we can offer you an overview and solutions by using the latest technologies 👩🏼‍💻, which can give you more security 🔐, to be an early adaptor 🥇 on your specific market or even save money 💵!

What does this mean for our techies and applicants?

At 47N you have great development possibilities 📈 and learn always new technologies. You are not stuck into a technology for years 🤷🏼‍♂️, that you miss new things. In our LABS unit and also with our Hackdayz you have the opportunity to develop awesome products and contribute a great environment for yourself and your teammates. Join us today in Zurich 🇨🇭, Konstanz 🇩🇪 or Skopje 🇲🇰.

Generate Spring Boot REST API using Swagger/OpenAPI

Reading Time: 5 minutes

Writing API definition is pretty cool stuff. It helps consumers to understand the API and agree on its attributes. In our company for that purpose we are using OpenAPI Specification (formerly Swagger Specification).

But the real deal is generating code and documentation from the specification file. In this blog I will show you how we are doing that in 47 North Labs

We will split this blog in two parts. The first part will be generating code, and the second part will be using the generated code.

Part 1

We are creating empty maven project named “demo-specification”.

Next thing is creating API definition file, api.yaml in src/main/resources/ directory. The demo content of this file is:

openapi: "3.0.0"
info:
  description: "Codegen for demo service"
  version: "0.0.1"
  title: "Demo Service Specification"
  contact:
    email: "antonie.zafirov@47northlabs.com"
tags:
  - name: "user"
    description: "User tag for demo purposes"
servers:
  - url: http://localhost:8000/
    description: "local host"
paths:
  /user/{id}:
    get:
      tags:
        - "user"
      summary: "Retrieves User by ID"
      operationId: "getUserById"
      parameters:
        - name: "id"
          in: "path"
          description: "retrieves user by user id"
          required: true
          schema:
            type: "integer"
            format: "int64"
      responses:
        200:
          description: "Retrieves family members by person id"
          content:
            application/json:
              schema:
                type: "object"
                $ref: '#/components/schemas/User'
components:
  schemas:
    User:
      type: "object"
      required:
        - "id"
        - "firstName"
        - "lastName"
        - "dateOfBirth"
        - "gender"
      properties:
        id:
          type: "integer"
          format: "int64"
        firstName:
          type: "string"
          example: "John"
        lastName:
          type: "string"
          example: "Smith"
        dateOfBirth:
          type: "string"
          example: "1992-10-05"
        gender:
          type: "string"
          enum:
            - "MALE"
            - "FEMALE"
            - "UNKNOWN"

Next step is updating pom.xml file

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.47northlabs</groupId>
    <artifactId>demo-specification</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <swagger-annotations-version>1.5.22</swagger-annotations-version>
        <jersey-version>2.27</jersey-version>
        <jackson-version>2.8.9</jackson-version>
        <jodatime-version>2.7</jodatime-version>
        <maven-plugin-version>1.0.0</maven-plugin-version>
        <junit-version>4.8.1</junit-version>
        <springfox-version>2.9.2</springfox-version>
        <threetenbp-version>1.3.8</threetenbp-version>
        <datatype-threetenbp-version>2.6.4</datatype-threetenbp-version>
        <spring-boot-starter-test-version>2.1.1.RELEASE</spring-boot-starter-test-version>
        <spring-boot-starter-web-version>2.1.0.RELEASE</spring-boot-starter-web-version>
        <junit-version>4.12</junit-version>
        <migbase64-version>2.2</migbase64-version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-annotations</artifactId>
            <version>${swagger-annotations-version}</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.core</groupId>
            <artifactId>jersey-client</artifactId>
            <version>${jersey-version}</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-multipart</artifactId>
            <version>${jersey-version}</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-json-jackson</artifactId>
            <version>${jersey-version}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.jaxrs</groupId>
            <artifactId>jackson-jaxrs-base</artifactId>
            <version>${jackson-version}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>${jackson-version}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>${jackson-version}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>${jackson-version}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.jaxrs</groupId>
            <artifactId>jackson-jaxrs-json-provider</artifactId>
            <version>${jackson-version}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-joda</artifactId>
            <version>${jackson-version}</version>
        </dependency>
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
            <version>${jodatime-version}</version>
        </dependency>
        <dependency>
            <groupId>com.brsanthu</groupId>
            <artifactId>migbase64</artifactId>
            <version>${migbase64-version}</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit-version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>${spring-boot-starter-test-version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${spring-boot-starter-web-version}</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>${springfox-version}</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>${springfox-version}</version>
        </dependency>
        <dependency>
            <groupId>org.threeten</groupId>
            <artifactId>threetenbp</artifactId>
            <version>${threetenbp-version}</version>
        </dependency>
        <dependency>
            <groupId>com.github.joschi.jackson</groupId>
            <artifactId>jackson-datatype-threetenbp</artifactId>
            <version>${datatype-threetenbp-version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.openapitools</groupId>
                <artifactId>openapi-generator-maven-plugin</artifactId>
                <version>3.3.4</version>
                <executions>
                    <execution>
                        <id>spring-boot-api</id>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                        <configuration>
                            <inputSpec>${project.basedir}/src/main/resources/api.yaml</inputSpec>
                            <generatorName>spring</generatorName>
                            <configOptions>
                                <dateLibrary>joda</dateLibrary>
                            </configOptions>
                            <library>spring-boot</library>
                            <apiPackage>com.northlabs.demo.api</apiPackage>
                            <modelPackage>com.northlabs.demo.api.model</modelPackage>
                            <invokerPackage>com.northlabs.demo.api.handler</invokerPackage>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.6.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-deploy-plugin</artifactId>
                <version>2.8.1</version>
                <executions>
                    <execution>
                        <id>default-deploy</id>
                        <phase>deploy</phase>
                        <goals>
                            <goal>deploy</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

After that, we are executing mvn clean install in the root directory of the project. The result is in target/generated-sources/ . com.northlabs.demo.api.UserApi generated API interface is what we need.

The magic is done by openapi-generator-maven-plugin. There are a lot of different generators that can be used, with a lot of options. Here is the list of them.

Part 2

Let’s create new spring boot project demo-service from https://start.spring.io/ .

What we need to do is to add demo-specification as a maven dependency in the demo-service project.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.4.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.47northlabs</groupId>
	<artifactId>demo-service</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>demo-service</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>com.47northlabs</groupId>
			<artifactId>demo-specification</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

In application.properties file we are setting server.port to 8000.

server.port=8000

Next step is creating a class UserRestController which will implement previously generated UserApi from demo-specification.

package com.northlabs.demoservice.rest.controller;

import com.northlabs.demo.api.UserApi;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserRestController implements UserApi {
}

Now, if we run the application and try to make GET request to /user/1 the response status will be 501 Not Implemented.

Let’s make some simple implementation of the API.

package com.northlabs.demoservice.rest.controller;

import com.northlabs.demo.api.UserApi;
import com.northlabs.demo.api.model.User;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserRestController implements UserApi {

    @Override
    public ResponseEntity<User> getUserById(@PathVariable("id") Long id) {
        User user = new User();
        user.setId(id);
        user.setFirstName("John");
        user.setLastName("Doe");
        user.setGender(User.GenderEnum.MALE);
        user.setDateOfBirth("01-01-1970");
        return ResponseEntity.ok(user);
    }
}

Now the response will be:

And we are done.

This is how we are implementing OpenAPI/Swagger in our projects.
In the next blog I will show you how you can provide Swagger UI, generate Java client, JavaScript client modify base paths etc.

Download the source code

Both projects are freely available on our Gitlab repository. Feel free to fix any mistakes and to comment here if you have any questions or feedback.

https://gitlab.com/47northlabs/public/openapi-codegen-demo/demo-specification

https://gitlab.com/47northlabs/public/openapi-codegen-demo/demo-service

Spring I/O, The Conference in Barcelona – 2019

Reading Time: 2 minutes

Spring I/O is the conference, which is leading the European Conference for the Spring Framework ecosystem. This year it will be the 8th edition and take place in Barcelona, Spain between 16 to 17 May and I’m going to attend it for the first time. This conference is also my first conference for this year, so I’m very excited 😊 about it.

Preparation

Initial preparation is done as mentioned below:

  • Ticket booking, The Conference ✔️
  • Flight booking, Zürich to Barcelona ✔️
  • Hotel booking ✔️

The Conference will take place in Palau de Congressos de Catalunya, Barcelona.

Location Palau de Congressos de Catalunya on Google Maps
The entrance

Topics

Detailed agenda and topics will be available here. But I’m interested in below-mentioned topics:

  • The State of Java Relational Persistence
  • Configuration Management with Kubernetes, a Spring Boot use-case
  • Moving beyond REST: GraphQL and Java & Spring
  • Spring Framework 5.2: Core Container Revisited
  • JUnit 5: what’s new and what’s coming
  • Migrating a modern spring web application to serverless
  • Relational Persistence with Spring Data JDBC [Workshop]
  • Clean Architecture with Spring
  • How to secure your Spring apps with Keycloak
  • Boot Loot – up your game and Spring like the pros
  • Spring Boot with Kotlin, Kofu and Coroutines
  • Multi-Service Reactive Streams Using Spring, Reactor, and RSocket
  • Zero Downtime Migrations with Spring Boot

Apart from the conference, I am planning to visit Font Màgica de Montjuïc, which is near to the conference venue.

I’m open to further suggestions regarding my visit to Barcelona. What else should I visit? Is there any special food that I should try?

Can Siri finally understand more than the predefined Intents?

Reading Time: 3 minutes

GUI is so 90’s

Lately, I find myself increasingly annoyed to have to use my phone to perform boring and recurring tasks like look up the quote of a special cryptocurrency. Especially in some circumstances like eg when I’m home. At home, I want to feel foremost comfortable. This is hard to achieve when I have to get up to search for my phone, once again. Wouldn’t it be nice to just ask in the room and get the answers?

Wait but there is Siri, right? So what can it do for me and what can developers achieve with it today?

Hey Siri, are we there yet?

Turns out that SiriKit offers a set of predefined intents ready to be used. That’s a start. But those cannot handle my specific requests and I guess a lot of others as well. To be fully usable something like custom parametrized intents would be nice. I would like that Siri understands something like:

“Hey Siri, what’s the price of <your cryptocurrency> in <your currency>?”

To be fair. When asking this for Bitcoin and USD you would get an answer. Depending on how the question is formulated Siri would start the Stocks app in preview or get something from the Web. But when trying to get an answer for other rather “unknown” cryptocurrencies, Siri struggles. I totally get that this question may seem fairly simple for a human to process but it is certainly not that simple for Siri to filter out the domain in question and start the “right” app for the job.

Hence I would also be satisfied with something in the form of a QA for the beginning:

> “Hey Siri, cryptocurrency price”

< “For what cryptocurrency?”

> “Bitcoin”

< “In what currency?”

> “USD”

In that way, developers could assign to specific keywords (in this case “cryptocurrency price”) input dialogues to get params to process those and render a response. Something similar to URL schemas

After looking a bit deeper I stumbled upon an interesting blog post which clarified it for me:

There are also some hands on blogposts how to set up “Custom Intents”:

I’ll just wait here then

Since iOS 12 it is possible to create a custom Intent in the form of an Intents.intentdefinition file. Here app developers can specify parameters which the app can process. To stick with the cryptocurrency example: When the user is searching for a price of a cryptocurrency inside an app, the app can create an Intent with the parameters already filled out. Eg. Show the price of Bitcoin in USD. Furthermore, the app can now “donate” this specific Intent (already parametrized) to the system. This “donation” would appear on the lock screen and as a shortcut ready to be used.

This means one could assign a custom Siri voice command to trigger this Intent. It also means that if you have 5 favourite cryptocurrencies and 3 favourite currencies you would have to go through this step 15 times inside the app. Afterwards, you would need to assign 15 voice commands to those donations.

Well, honestly this is not the way I would like it to be. But it’s a start and I hope that with iOS 13 we get something like parametrized Intents for the user to trigger.

Exploring the headless CMS functionality of AEM 6.5

Reading Time: 5 minutes

Adobe Experience Manager (AEM) is one of the leading enterprise content management system (CMS), formerly knows as Day CQ. The initial version was introduced in 2002, at a time when web projects were mostly implemented as static, server-side rendered websites. Content as well as styling information were mixed up within the same HTML document. Nowadays traditional websites are being more and more replaced and complemented by (mobile) applications which come up with their own presentation layer. Thus there is a need for a more flexible approach that separates content from styling, and that is able to deliver the data to multiple channels in a universal format. This requirement led to the emergence of so called headless content management systems, which usually supply the data in a RESTful manner (as JSON) to their consumers. This blog post summarizes the headless CMS extension provided by AEM.

Headless CMS in AEM

The headless CMS extension for AEM was introduced with version 6.3 and has been continuously improved since then, it mainly consists of the following components:

  • Content Services: Provides the functionality to expose user-defined content through a HTTP API in JSON format. This allows to deliver data to 3rd party clients other than AEM.
  • Content Fragments: Allows the user to insert/edit content as structured data entities. The schema of each content fragment is defined by a corresponding Content Fragment Model.

Note that AEM follows a hybrid approach, e.g. content fragments can either be delivered as JSON through the content services API, or embedded within a traditional HTML page. Visit Adobe’s headless CMS website for further information.

Example Project

There is a tutorial provided by Adobe where the concept of content services is explained in detail. It describes how to model the entries of a FAQ list by using content fragments, and how to expose this data through a API as JSON. The complete article can be found here.

The example is based on the existing We.Retail demo project that comes with the installation file of AEM. In summary, the following steps have to be performed:

  • First content fragment models should be enabled for the We.Retail project. From the AEM welcome page, go to ToolsConfiguration Browser, open the properties of the We.Retail configuration and ensure that the Content Fragment Models property has been selected.
  • Navigate to Tools → Assets → Content Fragment Models → We.Retail to create or edit content fragment models. Select the FAQ model and click on the edit button to open the Content Fragment Model Editor. Here you can edit the model structure by adding/removing elements using drag and drop.
  • The model can be used to create new content fragments which contain the actual data . To do this, navigate to Assets → Files → We.Retail → English → FAQs → Company. There is already content available here: Each entry of the FAQ list is modeled as a single fragment. The picture below shows the editor view for a FAQ content fragment.
  • To access the data through content services from outside, the FAQ items have to be embedded within a content page. Content fragments can be added to the page by drag and drop in the same way as any standard content component.
  • The content of the page can now be delivered as JSON via the “model” selector. The code section below shows an extract of the response of the FAQ page /content/we-retail/language-masters/en/faq.model.json
...
":items": {
        "contentfragment": {
          "title": "The Company Name",
          "description": "",
          "model": "we-retail/models/faq",
          "elements": {
            "question": {
              "title": "Question",
              "dataType": "string",
              "value": "What's with the name \"We.Retail\"?",
              ":type": "string"
            },
            "answer": {
              "title": "Answer",
              "dataType": "string",
              "paragraphs": [
                ""
              ],
              "value": "<p>We're not sure, but it sounds good!<br>\n</p>\n",
              ":type": "text/html"
            }
          },
          ":items": {},
          "elementsOrder": [
            "question",
            "answer"
          ],
          ":itemsOrder": [],
          ":type": "weretail/components/content/contentfragment"
        },
        "contentfragment_1811741936": {
          "title": "History",
...
  • Finally the data can now be consumed by any 3rd party application. The screenshot below shows an example made with vue.js, where the FAQ list is loaded from AEM content services by XHR request.

Conclusion

AEM content services provide a flexible way to deliver structured content to multiple channels, the data as well as its corresponding schema can be created and modified without any need for a deployment. However, the main focus of AEM is still on the authoring of backend-side rendered websites, but content services may be a good addition for environments where AEM is already in use.