Scala App Trait

Scala contains a trait called “App” and its used to turn objects into executable programs.

We do not need to explicitly define “main” method in a Scala object, instead the whole class body becomes the main method.

Refer the below example,

ScalaMainApp

In the above code, we define an object “ScalaMain” and in the body of that object, we define a function “add” for adding two numbers. The whole code section becomes the main method.

Java: Double brace initialization

“Double Brace Initialization” is a hidden feature of Java and used for initializing collection classes such as ArrayList, HashSet, and HashMap.

Even though the code looks more readable with this feature, be aware that it can cause memory issues.

In this post, we are going to see how we can use this with an example.

DoubleBraceInit

The output is given below,

{1=data1, 2=data2}

In the above code, dataMap is a HashMap which contains a key/value and double brace block contains the code to initialize this HashMap.

When a code contains a double brace block, then the compiler would generate an anonymous inner class which extends that collection class.

Let’s verify this with the above example. After compilation, I checked the target folder and it contains the below class files.

DoubleBraceInit-class

I opened up the DoubleBraceInitTester$1.class which is an anonymous inner class and it looks like below. So the compiler copied all the initialization code into the constructor of this class.

DoubleBraceInit-decompiler

 

 

JAX-RS: REST Streaming Response

In this post, we are going to see how to streaming a response with JAX-RS StreamingOutput.

StreamingOutput is an interface(https://docs.oracle.com/javaee/7/api/javax/ws/rs/core/StreamingOutput.html) and used as a resource method return value or as the entity in a Response when the application wishes to stream the output.

Consider that we have a list of person objects and each object contains first and last name and we want to create a RESTful web service to fetch the person details. Our goal is to stream the response instead of getting everything. Lets see how we can use StreamingOutput to achieve our goal.

The below is Person model class which contains two fields such as first name and last name.



package com.resource;

public class Person {

    private String firstName;
    private String lastName;

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}


The below is the Resource class and the method getDetails passes StreamingOutput to streamPersonData method of PersonService class.

Produces is “application/octet-stream” because we want to save the response as a file instead of rendering that in the browser.


package com.resource;

import com.service.PersonService;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;

@Path("/person")
public class PersonResource {

    @GET
    @Produces("application/octet-stream")
    @Path("details")
    public Response getDetails() {
        return Response.ok((StreamingOutput) new PersonService()::streamPersonData).build();
    }

}


The below is the PersonService class which contains the necessary logic to get the person details and convert the person object into JSON format and then write the converted JSON to OutputStream.

Because we are writing the output as JSON array, we are adding a comma symbol at the end of each person JSON output.


package com.service;

import com.model.Person;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

public class PersonService {

    private ObjectMapper objectMapper = new ObjectMapper();

    public void streamPersonDetails(OutputStream output) throws IOException {
        output.write('[');
        int i = 1;
        List personDetails = getPersonDetails();
        for (Person person : personDetails) {
            output.write(objectMapper.writeValueAsBytes(person));
            if (i < personDetails.size()) {
                output.write(',');
            }
            i++;
        }
        output.write(']');
    }

    private List getPersonDetails() {
        List personList = new ArrayList();
        for (int i = 0; i < 500; i++) {
            Person person = new Person();
            person.setFirstName("Peter:" + i);
            person.setLastName("Woods:" + i);
            personList.add(person);
        }
        return personList;
    }
}


The output is given below,

Streaming_response

If we want to render the response as “JSON” and view the response in browser, then we have to change the produces like this “@Produces(MediaType.APPLICATION_JSON)” and the output look like below,

Streaming_response_JSON

Scala Extractor Objects

An Extractor object is an object with an unapply method which takes an object and tries to give back its arguments.

As we all know that apply method of an Object takes arguments and creates an object and the unapply method will do the reverse.

Lets see this with an example.



object Customer {

  def apply(firstName: String, lastName: String) = firstName + "," + lastName

  def unapply(customerName: String): Option[String] = {
    val nameArray = customerName.split(",")
    if (nameArray.nonEmpty) nameArray.headOption else None
  }

  def main(args: Array[String]): Unit = {
    val customer = Customer("Balachandar", "Kuppusamy")

    customer match {
      case Customer(name) => println(s"FirstName is:$name")
      case _ => println("Could not extract Name")
    }
  }
}


In the above code, Customer is an object and the apply method takes first and last names and combine those names with a comma symbol and the unapply method takes the name and split it and then return the first name as an output.

Customer(“Balachandar”, “Kuppusamy”) is a shorthand for calling Customer.apply(“Balchandar”, “Kuppusamy”) and case Customer(name) is a shorthand for calling Customer.apply(name).

The output of the above program will look like below,


FirstName is:Balachandar


Java 8 – groupingBy Collector

In this post, we will see how to use groupingBy collector with an example.

Consider that we have a person class and it contains id, age, fullname and city fields. We have a list of person objects and we want to group by age. Lets see how we can do that with an example.

Here is the Person class.

Person.java



import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;

public class Person {

    private String id;

    private int age;

    private String fullName;

    private String city;

    public Person(String id, int age, String fullName, String city){
        this.id = id;
        this.age = age;
        this.fullName = fullName;
        this.city = city;
    }

    public String getId() {
        return id;
    }

    public int getAge() {
        return age;
    }

    public String getFullName() {
        return fullName;
    }

    public String getCity() {
        return city;
    }

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.SIMPLE_STYLE);

    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;

        if (o == null || getClass() != o.getClass()) return false;

        Person person = (Person) o;

        return new EqualsBuilder()
                .append(age, person.age)
                .append(id, person.id)
                .append(fullName, person.fullName)
                .isEquals();
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder(17, 37)
                .append(id)
                .append(age)
                .append(fullName)
                .toHashCode();
    }
}


To group the person list by age, the code is given below,


 //Group the person list by age
        Map<Integer, List> personListByAge = personList
                .stream()
                .collect(groupingBy(Person :: getAge));

The output will look like below,


{36=[id1,36,Peter,columbus, id3,36,Alex,hopkins], 37=[id2,37,John,columbus], 30=[id4,30,Ram,new york, id5,30,Bala,houston, id5,30,Bala,houston]}

By default, the groupingby collector returns a map with value as list of person objects. If you want to remove duplicates and collect the objects as set, then we have to pass the downstream parameter such as toSet().


  //Group the person list by age and remove duplicates
        Map<Integer, Set> personListByAgeNoDuplicates = personList
                .stream()
                .collect(groupingBy(Person :: getAge, toSet()));

The output will look like below,


{36=[id1,36,Peter,columbus, id3,36,Alex,hopkins], 37=[id2,37,John,columbus], 30=[id5,30,Bala,houston, id4,30,Ram,new york]}


If you want to group a person list by age and then again group the results by city, then we have to pass the groupingby(city) collector inside of the first groupingby.

Note that this will return a Map and an inner map which contains the group by field as key and the list of person objects.


 //Group the person list by age and then group the result of the first group by city

        Map<Integer, Map<String, List>> personListByAgeAndCity = personList
                .stream()
                .collect(groupingBy(Person :: getAge, groupingBy(Person :: getCity)));



The output will look like below,


{36={hopkins=[id3,36,Alex,hopkins], columbus=[id1,36,Peter,columbus]}, 37={columbus=[id2,37,John,columbus]}, 30={houston=[id5,30,Bala,houston, id5,30,Bala,houston], new york=[id4,30,Ram,new york]}}


The code is given below,

GroupByMain.java



import com.google.common.collect.Lists;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toSet;

public class GroupByMain {

    public static void main(String[] args) {

        Comparator comparator = Comparator.comparing(Person :: getAge);
        Person person1 = new Person("id1", 36, "Peter","columbus" );
        Person person2 = new Person("id2", 37, "John", "columbus");
        Person person3 = new Person("id3", 36, "Alex", "hopkins");
        Person person4 = new Person("id4", 30, "Ram", "new york");
        Person person5 = new Person("id5", 30, "Bala", "houston");
        Person person6 = new Person("id5", 30, "Bala", "houston");

        List personList = Lists.newArrayList(person1, person2, person3, person4, person5, person6);

        //Group the person list by age
        Map<Integer, List> personListByAge = personList
                .stream()
                .collect(groupingBy(Person :: getAge));

        System.out.println(personListByAge);

        //Group the person list by age and remove duplicates
        Map<Integer, Set> personListByAgeNoDuplicates = personList
                .stream()
                .collect(groupingBy(Person :: getAge, toSet()));

        System.out.println(personListByAgeNoDuplicates);

        //Group the person list by age and then group the result of the first group by city

        Map<Integer, Map<String, List>> personListByAgeAndCity = personList
                .stream()
                .collect(groupingBy(Person :: getAge, groupingBy(Person :: getCity)));

        System.out.println(personListByAgeAndCity);

    }
}