Java - ashish-ghub/docs GitHub Wiki

Java

Effective Java:

https://github.com/HugoMatilla/Effective-JAVA-Summary

What is Open JDK:

OpenJDK (Open Java Development Kit) is a [free and open-source] implementation of the Java Platform, Standard Edition (Java SE) of oracle. It is the result of an effort [Sun Microsystems]began in 2006. The implementation is licensed under the [GPL-2.0-only] with a . Were it not for the GPL linking exception, components that linked to the [Java class library] would be subject to the terms of the GPL license. OpenJDK is the official [reference implementation] of Java SE since version 7.

The OpenJDK project produces a number of components: most importantly the virtual machine (HotSpot), the Java Class Library and the Java compiler (javac). The web-browser plugin and Web Start, which form part of Oracle Java, are not included in OpenJDK. Sun previously indicated that they would try to open-source these components, but neither Sun nor Oracle have done so.The only currently available free plugin and Web Start implementations as of 2016 are those provided by IcedTea.

https://en.wikipedia.org/wiki/OpenJDK

diamond-problem

  • This is not present as java does not support multiple inheritance where 2 extended class has same function declaration this will lead to ambiguity.
  • Post Java 8 interface has default method which support interface function with default body(implementation) for all the implemented class.
  • Multiple Interfaces can be implemented by a single class, so if 2 default function with same declaration from at least 2 different interface will lead to issue so compiler does not allow and fails it at compilation.

https://www.tutorialspoint.com/what-is-diamond-problem-in-case-of-multiple-inheritance-in-java https://dzone.com/articles/dealing-with-diamond-problem-in-java

Java 8

default and static methods

Streams

Optional

New Local Date Time api to overcome Existing Date/ Time Apis

Java basics:

  1. Polymorphism is an object-oriented programming concept that refers to the ability of a variable, function, or object to take on multiple forms. In a programming language exhibiting polymorphism, class objects belonging to the same hierarchical tree (inherited from a common parent class) may have functions with the same name, but with different behaviors.

Example: The classic example is of the Shape class and all the classes that are inherited from it, such as:

Rectangle

Triangle

Circle

Types of polymorphism:

  1. Compile time polymorphism

Example: Method overloading

  1. Runtime polymorphism

Example: Method overriding

> Static polymorphism

Java, like many other OOP languages, allows you to implement multiple methods within the same class that use the same name. But, Java uses a different set of parameters called method overloading and represents a static form of polymorphism.

The parameter sets have to differ in at least one of the following three criteria:

They need to have a different number of parameters, one method accepting 2 and another one accepting 3 parameters The types of the parameters need to be different, one method accepting a String and another one accepting a Long They need to expect the parameters in a different order. For example, one method accepts a String and a Long and another one accepts a Long and a String. This kind of overloading is not recommended because it makes the API difficult to understand

2 The use of Class.forName()

Is use to dynamically load a class (object) at runtime without having a direct reference to it anywhere in the code at compile-time. You are using the classloader the same way the language does to load class definitions as needed.

Why would you do this? Dependency injection is a popular use of this feature. A lot of frameworks can allow you to define a class that will contain a implementation that the framework will need. If these references are done in configuration files, this allows you to load a class on-the-fly without knowing what it will be in advance.

3. Error handling use case:

  • When we aware we are going to allocation high memory so that time may be we can handle the exception to reduce memory allocation size

public class OutOfMemoryErrorExample {

public void createArray(int size) {
    try 
    {
        Integer[] myArray = new Integer[size];
    } 
    catch (OutOfMemoryError oome) {
        System.err.println("Array size too large");
        System.err.println("Max JVM memory: " + Runtime.getRuntime().maxMemory());
    }
}

public static void main(String[] args) {
    OutOfMemoryErrorExample oomee = new OutOfMemoryErrorExample();
    oomee.createArray(1000 * 1000 * 1000);
}

}

4. What is the difference between Checked and Unchecked Exceptions in Java?

Checked Exceptions should be handled in the code using try-catch block or else the method should use the throws keyword to let the caller know about the checked exceptions that might be thrown from the method. Unchecked Exceptions are not required to be handled in the program or to mention them in the throws clause of the method.

Exception is the superclass of all checked exceptions whereas RuntimeException is the superclass of all unchecked exceptions. Note that RuntimeException is the child class of Exception.

Checked exceptions are error scenarios that require to be handled in the code, or else you will get compile time error. For example, if you use FileReader to read a file, it throws FileNotFoundException and we must catch it in the try-catch block or throw it again to the caller method. Unchecked exceptions are mostly caused by poor programming, for example, NullPointerException when invoking a method on an object reference without making sure that it’s not null. For example, I can write a method to remove all the vowels from the string. It’s the caller’s responsibility to make sure not to pass a null string. I might change the method to handle these scenarios but ideally, the caller should take care of this.

5. Basic notes

  • A java file can have one public class and and other non public external class(s) without access specifier (i.e. default access specifier)
  • A Java class can have public structure like interface, enum , class
  • Abstract class does not need to implement interface method it can be done by class extending abstract class

package com.basic;

public class BasicClass {

public interface Task<T>
{
   T execute();
}
public enum Gender
{
   MALE, FEMALE;
}
public class Test1
{
   public Test1()
   {
      System.out.println("public inner class");
   }
}

}

class Test {

Test()
  {
   System.out.println("public outer non public class");
  }

}

//end of java file BasicClass.java


package com.test;

import com.basic.BasicClass;

import com.basic.BasicClass.Gender;

import com.basic.BasicClass.Task;

public class BasicTest implements Task{

public static void main(String[] args)
 {
   //inner public class can not be created without outer class
   BasicClass.Test1 t1 = new BasicClass().new Test1();
   System.out.println("print a gender value;" + Gender.MALE);

   // not allowed as differnet package
   // Test t = new Test();
 }

@Override
public String execute()
{
   return null;
}

}

6. String vs StringBuffer vs StringBuilder

String is immutable whereas StringBuffer and StringBuilder are mutable classes. StringBuffer is thread-safe and synchronized whereas StringBuilder is not. That’s why StringBuilder is faster than StringBuffer. String concatenation operator (+) internally uses StringBuffer or StringBuilder class. For String manipulations in a non-multi threaded environment, we should use StringBuilder else use StringBuffer class

Coupling and Cohesion

Coupling is the degree to which each program module relies on each one of the other modules. So, coupling is all about the relation between modules. Tightly coupled systems have a number of undesirable properties:

Changes in one module tend to have a ripple effect on other modules. (So it's hard to make isolated changes.) It will be hard to test a module in isolation. It will be hard to reuse a module in an alternative context.

Cohesion is a measure of how strongly-related or focused the responsibilities of a single module are. Systems with minimal cohesion have a number of undesirable properties:

(When applied to source code) code tends to be less readable. Code is likely to be less reusable in alternative contexts. Complexity is high. (It's hard to figure out what belongs where and why.) As a consequence, you should minimize coupling and maximize cohesion when designing your modules.

java-weak-reference https://www.baeldung.com/java-weak-reference

Q. What's the reason why Java doesn't allow us to do private T[] elements = new T[initialCapacity]; //compilation error

It's because Java's arrays (unlike generics) contain, at runtime, information about its component type. So you must know the component type when you create the array. Since you don't know what T is at runtime, you can't create the array. So it should be private Object[] elements; T element = (T) elements[--size];

Serialization:

https://www.oracle.com/technical-resources/articles/java/serializationapi.html

https://www.baeldung.com/java-serialization

1 Introduction Serialization is the conversion of the state of an object into a byte stream; deserialization does the opposite. Stated differently, serialization is the conversion of a Java object into a static stream (sequence) of bytes, which we can then save to a database or transfer over a network.

  1. Serialization and Deserialization The serialization process is instance-independent; for example, we can serialize objects on one platform and deserialize them on another. Classes that are eligible for serialization need to implement a special marker interface, Serializable.

Both ObjectInputStream and ObjectOutputStream are high level classes that extend java.io.InputStream and java.io.OutputStream, respectively. ObjectOutputStream can write primitive types and graphs of objects to an OutputStream as a stream of bytes. We can then read these streams using ObjectInputStream.

The most important method in ObjectOutputStream is:

  • public final void writeObject(Object o) throws IOException; This method takes a serializable object and converts it into a sequence (stream) of bytes. Similarly, the most important method in ObjectInputStream is:

  • public final Object readObject() throws IOException, ClassNotFoundException; This method can read a stream of bytes and convert it back into a Java object. It can then be cast back to the original object.

Let's illustrate serialization with a Person class. Note that static fields belong to a class (as opposed to an object) and are not serialized. Also, note that we can use the keyword transient to ignore class fields during serialization:

 public class Person implements Serializable {
     private static final long serialVersionUID = 1L;
     static String country = "ITALY";
     private int age;
     private String name;
     transient int height;
 
     // getters and setters
 }

The test below shows an example of saving an object of type Person to a local file, and then reading the value back in:

 @Test 
 public void whenSerializingAndDeserializing_ThenObjectIsTheSame() throws IOException, ClassNotFoundException { 
     Person person = new Person();
     person.setAge(20);
     person.setName("Joe");
     
     FileOutputStream fileOutputStream = new FileOutputStream("yourfile.txt");
     ObjectOutputStream objectOutputStream  = new ObjectOutputStream(fileOutputStream);
     objectOutputStream.writeObject(person);
     objectOutputStream.flush();
     objectOutputStream.close();
     
     FileInputStream fileInputStream = new FileInputStream("yourfile.txt");
     ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
     Person p2 = (Person) objectInputStream.readObject();
     objectInputStream.close(); 
  
     assertTrue(p2.getAge() == person.getAge());
     assertTrue(p2.getName().equals(person.getName()));
 }

We used ObjectOutputStream for saving the state of this object to a file using FileOutputStream. The file “yourfile.txt” is created in the project directory. This file is then loaded using FileInputStream. ObjectInputStream picks this stream up and converts it into a new object called p2.

Finally, we'll test the state of the loaded object, and ensure it matches the state of the original object.

Note that we have to explicitly cast the loaded object to a Person type.

3. Java Serialization Caveats

There are some caveats which concern serialization in Java.

3.1. Inheritance and Composition When a class implements the java.io.Serializable interface, all its sub-classes are serializable as well. Conversely, when an object has a reference to another object, these objects must implement the Serializable interface separately, or else a NotSerializableException will be thrown:

 public class Person implements Serializable {
     private int age;
     private String name;
     private Address country; // must be serializable too
 }

If one of the fields in a serializable object consists of an array of objects, then all of these objects must be serializable as well, or else a NotSerializableException will be thrown.

3.2. Serial Version UID The JVM associates a version (long) number with each serializable class. We use it to verify that the saved and loaded objects have the same attributes, and thus are compatible on serialization.

Most IDEs can generate this number automatically, and it's based on the class name, attributes, and associated access modifiers. Any changes result in a different number, and can cause an InvalidClassException.

If a serializable class doesn't declare a serialVersionUID, the JVM will generate one automatically at run-time. However, it's highly recommended that each class declares its serialVersionUID, as the generated one is compiler dependent and thus may result in unexpected InvalidClassExceptions.

3.3. Custom Serialization in Java Java specifies a default way to serialize objects, but Java classes can override this default behavior. Custom serialization can be particularly useful when trying to serialize an object that has some unserializable attributes. We can do this by providing two methods inside the class that we want to serialize:

private void writeObject(ObjectOutputStream out) throws IOException;

and

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException;

With these methods, we can serialize the unserializable attributes into other forms that we can serialize:

public class Employee implements Serializable {
    private static final long serialVersionUID = 1L;
    private transient Address address;
    private Person person;

    // setters and getters

    private void writeObject(ObjectOutputStream oos) 
      throws IOException {
        oos.defaultWriteObject();
        oos.writeObject(address.getHouseNumber());
    }

    private void readObject(ObjectInputStream ois) 
      throws ClassNotFoundException, IOException {
        ois.defaultReadObject();
        Integer houseNumber = (Integer) ois.readObject();
        Address a = new Address();
        a.setHouseNumber(houseNumber);
        this.setAddress(a);
    }
}
public class Address {
    private int houseNumber;

    // setters and getters
}

We can run the following unit test to test this custom serialization:

@Test
public void whenCustomSerializingAndDeserializing_ThenObjectIsTheSame() 
  throws IOException, ClassNotFoundException {
    Person p = new Person();
    p.setAge(20);
    p.setName("Joe");

    Address a = new Address();
    a.setHouseNumber(1);

    Employee e = new Employee();
    e.setPerson(p);
    e.setAddress(a);

    FileOutputStream fileOutputStream
      = new FileOutputStream("yourfile2.txt");
    ObjectOutputStream objectOutputStream 
      = new ObjectOutputStream(fileOutputStream);
    objectOutputStream.writeObject(e);
    objectOutputStream.flush();
    objectOutputStream.close();

    FileInputStream fileInputStream 
      = new FileInputStream("yourfile2.txt");
    ObjectInputStream objectInputStream 
      = new ObjectInputStream(fileInputStream);
    Employee e2 = (Employee) objectInputStream.readObject();
    objectInputStream.close();

    assertTrue(
      e2.getPerson().getAge() == e.getPerson().getAge());
    assertTrue(
      e2.getAddress().getHouseNumber() == e.getAddress().getHouseNumber());
}

In this code, we can see how to save some un-serializable attributes by serializing Address with custom serialization. Note that we must mark the un-serializable attributes as transient to avoid the NotSerializableException.

What happens if you try to send non-serialized Object over network?

When traversing a graph, an object may be encountered that does not support the Serializable interface. In this case the NotSerializableException will be thrown and will identify the class of the non-serializable object.

Why Do We Need Serialization in Java

Some use-cases for serialization in Java include:

** a) Cross-machine synchronization**

The serialization protocol generates byte streams that work across different architectures and operating systems, allowing for synchronization between different JVMs. Like RMI, Socket communication between two java process

b) Caching

Object serialization saves the state of an object, whereas deserialization takes little time to recreate the original object compared to building it from a Java class, saving time when accessing objects from cache memory.

c) Replication

Byte streams can easily be shared across Java Virtual Machines that serialize them in little time. This allows for the provision of multiple object clones across different machines/environments for simple replication.

d) Multi-tenant communication

Once the original object has been serialized, data structures can be transferred efficiently through a network of machines, allowing for exchanging information between different environments.

e) Persistence

After applying serialization, Java can store the state of any object in a database or a file system that can be used later.

** do all dtos need to be serialized in rest call ** (https://stackoverflow.com/questions/37731728/do-all-dtos-need-to-be-serialized-in-rest-call)

To strictly answer your question, No. you do not need to serialize the DTO, since serialization is relevant where an object is serialized/de-serialized to/from byte stream, in your case json serialization first happens to a string and then byte stream. So as long as the String class (or whatever native classes) that your Json parser library uses, is serialized, you are safe.

However it is always best practice to serialize a deeply normalized dto/entity/pojo since you never know where it might be used tomorrow.

Stop That Serialization!

OK, we have seen quite a bit about the serialization process, now let's see some more. What if you create a class whose superclass is serializable but you do not want that new class to be serializable? You cannot unimplemented an interface, so if your superclass does implement Serializable, your new class implements it, too (assuming both rules listed above are met). To stop the automatic serialization, you can once again use the private methods to just throw the NotSerializableException. Here is how that would be done:

 private void writeObject(ObjectOutputStream out) throws IOException
  {
 throw new NotSerializableException("Not today!");
  }
 
 private void readObject(ObjectInputStream in) throws IOException
  {
 throw new NotSerializableException("Not today!");
  }

Create Your Own Protocol: the Externalizable Interface

Our discussion would be incomplete not to mention the third option for serialization: create your own protocol with the Externalizable interface. Instead of implementing the Serializable interface, you can implement Externalizable, which contains two methods:

public void writeExternal(ObjectOutput out) throws IOException; public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;

Just override those methods to provide your own protocol. Unlike the previous two serialization variations, nothing is provided for free here, though. That is, the protocol is entirely in your hands. Although it's the more difficult scenario, it's also the most controllable. An example situation for that alternate type of serialization: read and write PDF files with a Java application. If you know how to write and read PDF (the sequence of bytes required), you could provide the PDF-specific protocol in the writeExternal and readExternal methods.

Just as before, though, there is no difference in how a class that implements Externalizable is used. Just call writeObject() or readObject and, voila, those externalizable methods will be called automatically.

Serialization Vulnerabilities

        ----

The serialization process is crucial for Java applications since it provides a standard data structure and enables objects portability. Despite the benefits serialization in Java offers, such applications are susceptible to serialization vulnerabilities where attackers can insert malicious objects into the runtime environment to compromise user or system data. These objects typically include payloads and private methods that run executable code on target JVMs. Once the attacker can control the data being serialized and deserialized, they can control program objects and in-memory variables, influencing the code flow within the application. The application is also susceptible to attacks if the object contains classes whose behavior can be altered during the deserialization process. In such cases, attackers can exploit existing data structures, change their contents, overwrite existing variables and exploit other vulnerabilities within the serialization mechanism.

Insecure Serialization Attacks – Risk Factors Serialization attacks are less likely to be performed automatically, as plenty of manual work is required to create a malicious object that the serialization mechanism considers valid. Once the hacker has successfully compiled the exploit on one JVM, they can execute malicious code remotely on all other machines hosting the same application. Once attackers gain control over the source code, they assume a complete host takeover of the vulnerable application. In such cases, detecting a successful exploit is highly complex.

Potential factors that cause serialization attacks in Java include:

a) Deserializing objects from untrusted sources Most attacks occur since development and operations teams fail to validate user-supplied data before deserializing an object. For applications that rely on the binary serialization format, developers assume that users cannot effectively read and manipulate object data, so they deem all deserialized objects trustworthy. With some effort, an attacker can craft exploits and inject malicious payloads into binary serialized objects, allowing them to abuse the application’s logic.

** b) A large number of dependencies ** Typical Java applications/websites implement numerous libraries, each having its dependencies. Therefore, an application comprises many methods and classes that can be difficult to manage securely. This makes it difficult to predict and prevent a serialization attack since a hacker can replicate any class and invoke one method to execute their malicious payload. Hackers can also connect several unexpected method invocations, so the final data parsed into the sink (file system, database, etc.) is entirely different from the initial input. Since developers can not anticipate the flow of data in the application, it is almost impossible to address every security gap opened by the serialization vulnerability.

Java Serialization Attack Approaches

There are multiple ways to exploit insecure serialization vulnerabilities in Java. These include:

a) Modifying object attributes If the attacker preserves a valid serialized object while tampering with its static fields, the deserialization process creates a server-side object with altered attribute values. Hackers mainly use this technique to identify and modify user access permissions in HTTP requests, allowing for unauthorized privilege escalation.

b) Modifying data types Attackers leverage serialization flaws to supply unexpected data types to abuse Java application logic. In such a case, the hacker builds malicious code that leverages loose comparisons to manipulate the machine into accepting user-supplied data from a deserialized object. The hacker can then use this data to bypass security controls such as authorization and session authentication mechanisms.

c) Extending application functionality This approach involves using a Java website/application’s functionality to execute malicious processes on a data set in a deserialized object. This functionality is entirely user-accessible, and the hacker could manually or automatically pass data into risky methods.

Preventing Serialization Attacks in Java

Some best practices to prevent serialization vulnerabilities include:

a) Use non-native formats

Developers should use standard data formats such as XML and JSON, eliminating the chances of attackers repurposing custom deserialization logic for remote code execution. These non-native formats implement a secure data transfer pattern that creates a separate serialization protocol for objects and state transfer, making the serialization algorithm unavailable to external entities.

b) Use RASP to prevent remote code execution

Runtime Application Self-Protection (RASP) tools are deployed into application servers to intercept all communications between the host and client machines and detect attacks in real-time. These tools continuously monitor data flows, systems, and user behavior to detect malicious activity. These tools also identify patterns in data structures and serializable objects to build context for regular user and application behavior. Any out-of-context data input is considered a potential threat. RASP tools can be configured to alert teams of attack attempts in diagnostic mode or mitigate the attacks in protection mode.

c) Implement checks for data integrity/Deserialize signed data

Complement blacklisting and pattern-matching techniques with signature-based positive validation techniques to ensure user-provided data is trustworthy. Additionally, implement sufficient authorization/authentication checks to verify the source of the input byte-stream before deserializing it.

d) Use custom deserialization methods

OWASP provides a cheat sheet with guidelines on building custom serialization and deserialization code to enumerate safe validation methods. These guidelines can be used to ensure the application is free of untrusted data.

e) Restrict classes to be serialized by subclassing java.io.ObjectInputStream

The java.io.ObjectInputStream class deserializes objects whose security can be hardened by sub-classing them. This is achieved by overriding the ObjectInputStream.html#resolveClass(), which restricts the classes that can be deserialized. Security teams can also deploy an agent that secures all usage of the java.io.ObjectInputStream class to harden applications against unknown malicious data types.

f) Use a vulnerability detection tool

Deploy a security testing tool that identifies static and dynamic applications vulnerabilities through continuous scanning and testing. The Crashtest Security Suite helps scan APIs and web applications to identify serialization vulnerabilities before attackers exploit them. Sign up for a free trial to begin a quick and efficient vulnerability scanning.

Must read blogs om Serialization:

https://www.digitalocean.com/community/tutorials/serialization-in-java#serialization-with-inheritance

Java Non blocking IO


Java release, internals, JVM



Java useful tools & Libs;

  • Java Object Layout (JOL) : calculate java object size

JOL (Java Object Layout) is the tiny toolbox to analyze object layout in JVMs. These tools are using Unsafe, JVMTI, and Serviceability Agent (SA) heavily to decode the actual object layout, footprint, and references. This makes JOL much more accurate than other tools relying on heap dumps, specification assumptions, etc.

https://github.com/openjdk/jol

⚠️ **GitHub.com Fallback** ⚠️