Thursday, May 12, 2022

Maven plugin configuration without editing POM xml

 Usually maven plug-ins are configured by modifying the POM xml file. For example, in the following configuration POM file is edited to set the expected source and target for the maven-compiler-plugin

<plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.7.0</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin>


In some scenario, we may not have option to modify the POM file. In those conditions, we can configure the plugin by adding the configuration in the command line. For example, in the command below the maven-compiler-plugin is configured using command line arguments without modifying the POM file.

mvn install -Dmaven.compiler.source=1.7 -Dmaven.compiler.target=1.7


Note: The configuration set in the command line is not same as in the POM file. We should set User property in the command line. The User property should be available in the plugin documentation. For example, https://maven.apache.org/plugins/maven-compiler-plugin/compile-mojo.html


Friday, February 11, 2022

Clean code - Optional comparison

Following is an example of writing less verbose and clean code for optional value comparison. This code (isAbc2) avoids unnecessary IF condition. The code sample also has a way to compare clean code and legacy code for a safety.


import java.util.Optional;

public class C1 {
	public static void main(String[] arg) {
		Optional val = Optional.of("abc");
		Optional noval = Optional.empty();
		Optional def = Optional.of("def");
		
		System.out.println(isAbc1(val) == isAbc2(val));
		System.out.println(isAbc1(noval) == isAbc2(noval));
		System.out.println(isAbc1(def) == isAbc2(def));
		
	}
	
	private static boolean isAbc1(Optional op) {
		if(op.isPresent()) {
			return op.get().equals("abc");
		}
		return false;
	}

	// clean code
	private static boolean isAbc2(Optional op) {
		return op.map("abc"::equals).orElse(false);
	}
}


The result of the above code in JDK 11.

true
true
true

Thursday, February 11, 2021

Compact code with flatMap for methods returning Optional

Compact code with flatMap for methods returning Optional. flatMap() method is available both in Stream and Optional. flatMap method can help in writing compact code as shown below. Moreover several article suggest to avoid using get() in Optional. flatMap() can also help in avoiding get() as shown below.



import java.util.List;
import java.util.Optional;

public class OpMap {
    
    public static void main(String[] arg) {
        Emp emp = new Emp();
        
        String dname = emp.getDept()
                .map(Dept::getName)
                .orElse("temp");
        System.out.println(dname);
        
        dname = emp.getDept()
                .map(Dept::getOptionalName)
                .orElse(Optional.empty()) // This is bad
                .orElse("temp");
        System.out.println(dname);
        
        dname = emp.getDept()
                .map(Dept::getOptionalName)
                .filter(Optional::isPresent) // This is bad
                .map(Optional::get) // This is bad
                .orElse("temp");
        System.out.println(dname);
        
        dname = emp.getDept()
                .flatMap(Dept::getOptionalName) // Better option
                .orElse("temp");
        System.out.println(dname);
        
        List emps = List.of(new Emp());
        dname = emps.stream()
                .map(Emp::getDept)
                .filter(Optional::isPresent) // This is bad  
                .map(Optional::get) // This is bad
                .map(Dept::getOptionalName)
                .filter(Optional::isPresent) // This is bad
                .map(Optional::get) // This is bad
                .findFirst().orElse("temp");
        System.out.println(dname);
        
        dname = emps.stream()
                .map(Emp::getDept)
                .flatMap(Optional::stream) // Better option
                .map(Dept::getOptionalName)
                .flatMap(Optional::stream) // Better option
                .findFirst().orElse("temp");
        System.out.println(dname);
                
    }
    
    static class Emp {
        private String eName;
        private Dept dept;
        
        public Optional geteName() {
            return Optional.ofNullable(eName);
        }
        
        public void seteName(String eName) {
            this.eName = eName;
        }
        
        public Optional getDept() {
            return Optional.ofNullable(dept);
        }
        
        public void setDept(Dept dept) {
            this.dept = dept;
        }
    }
    
    static class Dept {
        private String dName;
        
        public String getName() {
            return dName;
        }
        
        public Optional getOptionalName() {
            return Optional.ofNullable(dName);
        }
        
        public void setdName(String dName) {
            this.dName = dName;
        }
    }
    
}
  

Wednesday, February 21, 2018

Git add, commit and push in single command

We can replace frequently used multiple git commands like add, commit and push in a single command.

Multiple step Git add, commit, push

git add .
git commit -m "message"
git push

Single step Git add, commit and push
git commit -am "message" && git push 

Sunday, November 19, 2017

Serialize & Deserialize exactly same as JAX-RS server

The following code sample show a way to serialize and deserialize exactly same as the JAX-RS server. The code used the same MessageBodyReader  and  MessageBodyWriter used while Jersey frameworks converts request and response body.

The annotation javax.ws.rs.core.Context  is the key. The Providers used by the framework can be fetched from the context.

I have used this technique to improve the performance of the GET call. There are no serialization and deserialization during the GET call. It helps in improving the performance



import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;

import org.springframework.stereotype.Component;

@Path("/emp")
@Produces({ MediaType.APPLICATION_JSON })
@Component
public class EmpResource {
    
    @Context
    javax.ws.rs.ext.Providers providers;
    
    @POST
    public Employee post(Employee emp) {
        //convert POJO to String
        MessageBodyWriter writer = providers.getMessageBodyWriter(Employee.class,
                Employee.class, null, MediaType.APPLICATION_JSON_TYPE);
        String jsonString = null;
        try {
            ByteArrayOutputStream entityStream = new ByteArrayOutputStream();
            writer.writeTo(emp, Employee.class, Employee.class, null,
                    MediaType.APPLICATION_JSON_TYPE, null, entityStream);
            jsonString = entityStream.toString();
            // Business logic
            //Store jsonString to back end
        } catch (IOException e) {}
        
        //convert String to POJO
        MessageBodyReader reader = providers.getMessageBodyReader(Employee.class,
                Employee.class, null, MediaType.APPLICATION_JSON_TYPE);
        Employee emp2 = null;
        try {
            emp2 = reader.readFrom(Employee.class, Employee.class, null,
                    MediaType.APPLICATION_JSON_TYPE, null,
                    new ByteArrayInputStream(jsonString.getBytes()));
        } catch (Exception e) {}
        
        return emp2;
    }
    
    @GET
    public String get(@QueryParam("id") String id) {
        //Read from backend
        String jsonString = null;

        //Performance improvement: Avoiding String-POJO-String conversion
        return jsonString;
    }
    
}




Sunday, August 20, 2017

Java stream: Logging before filter

While iterating in Java Streams, we may need to log all the items processed by the stream. Especially when using filter in the stream. We can use Peek api for achieving the same.

The following ready to run code will help try out.

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class LogStream {
    public static void main(String[] args) {
        System.out.println("Log");
        List result = data().stream()
                .peek(e -> System.out.println(e.getSalary()))
                .filter(e -> e.getSalary()
                        .doubleValue() < 2)
                .collect(Collectors.toList());
        System.out.println("Result");
        result.forEach(e -> System.out.println(e.getSalary()));
    }
    
    static class Emp {
        public Emp(String name, String dept, BigDecimal salary) {
            super();
            this.name = name;
            this.dept = dept;
            this.salary = salary;
        }
        
        private String name;
        private String dept;
        private BigDecimal salary;
        
        public String getName() {
            return name;
        }
        
        public String getDept() {
            return dept;
        }
        
        public BigDecimal getSalary() {
            return salary;
        }
    }
    
    private static List data() {
        Emp e1 = new Emp("e1", "dept1", BigDecimal.valueOf(1.1));
        Emp e2 = new Emp("e2", "dept1", BigDecimal.valueOf(1.1));
        Emp e3 = new Emp("e3", "dept2", BigDecimal.valueOf(2.1));
        Emp e4 = new Emp("e4", "dept2", BigDecimal.valueOf(1.9));
        return Arrays.asList(e1, e2, e3, e4);
    }
    
}


Monday, February 20, 2017

Java 8 stream - GroupingBy sum BigDecimal - summarizingBigDecimal

Java 8 stream - GroupingBy and summing a BigDecimal field

 import java.math.BigDecimal;  
 import java.util.Arrays;  
 import java.util.List;  
 import java.util.Map;  
 import java.util.stream.Collectors;  
 public class C1 {  
      public static void main(String[] arg){  
           Map<String, BigDecimal> result = data().stream()
               .collect(Collectors.groupingBy(Emp::getDept, 
                        Collectors.mapping(Emp::getSalary, Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));  
           System.out.println(result);  
      }  
      static class Emp{  
           public Emp(String name, String dept, BigDecimal salary) {  
                super();  
                this.name = name;  
                this.dept = dept;  
                this.salary = salary;  
           }  
           private String name;  
           private String dept;  
           private BigDecimal salary;  
           public String getName() {  
                return name;  
           }  
           public String getDept() {  
                return dept;  
           }  
           public BigDecimal getSalary() {  
                return salary;  
           }  
      }  
      private static List<Emp> data(){  
           Emp e1 = new Emp("e1", "dept1", BigDecimal.valueOf(1.1));  
           Emp e2 = new Emp("e2", "dept1", BigDecimal.valueOf(1.1));  
           Emp e3 = new Emp("e3", "dept2", BigDecimal.valueOf(2.1));  
           Emp e4 = new Emp("e4", "dept2", BigDecimal.valueOf(1.9));  
           return Arrays.asList(e1, e2, e3, e4);  
      }  
 }  

If Salary is Integer or Long or Double, Collectors class provides direct method for summing. Eg: summarizingInt, summarizingLong, summarizingDouble. Always prefer to use methods from JDK instead of writing your own code.