Search This Blog

Monday, September 6, 2021

Lombok or Not

What's Lombok

Lombok creates Java code during compilation based on annotations, so you don't have to write code.

Most popular annotations:

  • @Data/@Value - create (immutable) data class
  • @Builder - create a builder for a class
  • @Sl4jf - add logger definition 
  • @ToString - toString to list all fields
  • @XXXArgsConstructor - create specified constructor

Example

@Data
@Builder
class Person {
String firstName;
String lastName;
 }

Generated code

class Person {
String firstName;
String lastName;

Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}

public static PersonBuilder builder() {
return new PersonBuilder();
}

public String getFirstName() {
return this.firstName;
}

public String getLastName() {
return this.lastName;
}

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

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

public boolean equals(final Object o) {
if (o == this) return true;
if (!(o instanceof Person)) return false;
final Person other = (Person) o;
if (!other.canEqual((Object) this)) return false;
final Object this$firstName = this.getFirstName();
final Object other$firstName = other.getFirstName();
if (this$firstName == null ? other$firstName != null :
!this$firstName.equals(other$firstName)) return false;
final Object this$lastName = this.getLastName();
final Object other$lastName = other.getLastName();
if (this$lastName == null ? other$lastName != null
!this$lastName.equals(other$lastName)) return false;
return true;
}

protected boolean canEqual(final Object other) {
return other instanceof Person;
}

public int hashCode() {
final int PRIME = 59;
int result = 1;
final Object $firstName = this.getFirstName();
result = result * PRIME + ($firstName == null ? 43 :
$firstName.hashCode());
final Object $lastName = this.getLastName();
result = result * PRIME + ($lastName == null ? 43 :
$lastName.hashCode());
return result;
}

public String toString() {
return "Person(firstName=" +
this.getFirstName() + ", lastName=" +
this.getLastName() + ")";
}

public static class PersonBuilder {
private String firstName;
private String lastName;

PersonBuilder() {
}

public PersonBuilder firstName(String firstName) {
this.firstName = firstName;
return this;
}

public PersonBuilder lastName(String lastName) {
this.lastName = lastName;
return this;
}

public Person build() {
return new Person(firstName, lastName);
}

}
}

Thoughts on Lombok

 ‎
✔ Saves you some/a lot typing
✔ Generates boilerplate code that is tedious to write correctly
Needs proper tooling and IDE support
✗ Hard to debug the generated code (even though it's rarely needed)
✗ Might decrease code quality (coupling; large classes; invalid state builders, etc.)
✗ Code Quality tools can be tricked by the generated code (e.g flagging generated code as non-standard)
✗ Errors in Lombok and in tools

Advice (my view)

 ‎
Whenever possible use IDE to generate/update boilerplate code for you.

More specifically:
  • Don't use @Log (generate by IDE; only 2 lines gained) 
  • Don't use @XXXArgsConstructor (generate by IDE; it's easier to debug and watch)
  • @Data and @Builder can be helpful for more complex classes 
    • alternative A: Java records
    • alternative B: Apache builders (org.apache.commons.lang3.builder.xxx)
    • alternative C: IDE generated code with @EqualsAndHashCode

Thursday, October 19, 2017

Developer Experience Lessons At Netflix

Netfix provides a great overview on how they operate a huge microservice, serverless stack, including:

  • How effortless is the local development experience?
  • Are deployment artifacts portable, easy to version and manage?
  • What are the implications of increased development velocity
  • Can fine-grained functions be composed rapidly with confidence?
Read part1 and part2.  

Wednesday, October 18, 2017

Issues with Large Scale Microservices

Issues with Large Scale Microservices

  • Complexity
    • A new feature request modifies multiple services, coordination for
      • API
      • Protocols
      • Development schedule
    • Dependency between services → exposing internals
    • Running the whole system locally is problematic for developers → setup
  • Service Communication
    • Direct
    • Message middle-ware
  • Production Database Access
    • Duplicated database
    • Write-read-trough 
      • Write to a develop database
      • Try to read from production database
        • If data found → return
        • If data not found → read from develop database

Friday, February 5, 2016

Character Encoding Changes in Tomcat 8 for GET Requests

HTTP GET requests (url+parameters) are treated as ASCII characters by default. Non-ASCII values, however, need to be converted to ASCII by using escape sequences. 

This conversion behavior has been changed in Tomcat 8:
  • Before Tomcat 8 the default character encoding of the entire GET request was ISO-8859-1, so if your request contains UTF-8 characters (which is very common) you need to manually decode the escaped (ASCII) text back to UTF-8.
  • Starting with Tomcat 8 the entire GET request is treated as UTF-8 by default but this can be changed to conform with the servlet specification.

Friday, January 22, 2016

Quick and Dirty jstatd Setup on Linux



What is jstatd?

 

"The jstatd tool is an RMI server application that monitors for the creation and termination of instrumented HotSpot Java virtual machines (JVMs) and provides a interface to allow remote monitoring tools to attach to JVMs running on the local host." [source]

NOTE: jstatd is not required for JMX connections;

How to setup jstatd on a Linux server?


A) login as root (told you - it's dirty)

B) create the jstatd.all.policy file in the home folder (/root) with the following content: 

   grant codebase "file:/opt/jdk1.8.0_45/lib/tools.jar" {
       permission java.security.AllPermission;
   };


     NOTE: don't forget to change the path of the JDK

C) run jstatd:

   ./jstatd -p 1099 
     -J-Djava.security.policy=/root/jstatd.all.policy
     -J-Djava.net.preferIPv4Stack=true
     -J-Djava.rmi.server.hostname=172.17.1.143

      -p                                         listen port for jstat daemon 
      java.security.policy             policy file to use (created above)
      java.net.preferIPv4Stack     use IPv4 (optional if IPv6 not used)
      java.rmi.server.hostname    listen on this interface (optional)

      NOTE: add & to run jstatd in background 

D) now you should be able to monitor this server using VisualVM.    


 


Wednesday, July 9, 2014

Utility Class Using Enum


A utility class using enum:

public enum StringUtil
{
    ;  // enum terminator

    public static void boo ()
    {
        // ...
    }
}

A utility class using class:

public final class StringUtil
{
    public static void boo () {
        // ...
    }

    private StringUtil() {
        // no-init ctor
    }   
}

When using Enum

    ✔ no need for constructor
    ✔ singleton by default
    ✖ automatically extends base Enum class
    ✖ ihnerited Enum methods (name, etc.) available for utility class user
    ✖ Enum static methods (values, etc.) available for utility class user

Friday, January 10, 2014

On-Demand Exporting a Spring Bean via JMX


1) Define the bean to be exported

 <bean id="myBean" class="...." />

2) Define a MBeanExporter

 <bean id="mbeanExporter" class="org.springframework.jmx.export.MBeanExporter" />

2) Get the exporter

 ApplicationContext applicationContext = ...
 MBeanExporter beanExporter = (MBeanExporter) applicationContext.getBean("mbeanExporter");

3) Export the bean

 beanExporter.registerManagedResource(applicationContext.getBean("myBean"), 
                ObjectName.getInstance("com.company:type=Users,name=User-A"));

4) Bean is now accessible via JMX


5) Unregister (if needed)

 beanExporter.unregisterManagedResource (ObjectName.getInstance("com.company:type=Users,name=User-A"));