Monday, December 12, 2022

Efficient JSON serialization with Jackson and Java


When you’re building distributed systems in Java, the problem of serialization naturally arises. Briefly, serialization is the act of creating a representation of an object to store or transmit it and then reconstruct the same object in a different context.

Oracle Java Certification, Oracle Java Career, Java Jobs, Java Prep, Java Tutorial and Materials, Java Learning, Oralce Java JSON

That context could be

◉ Needing the same object in the same JVM but at a different time
◉ Needing the same object in a different JVM, which might be on a different machine
◉ Needing the same object in a non-JVM application

The last of these possibilities deserves a bit more thought. On the one hand, working with a non-JVM application opens the possibility of sharing objects with the whole world of network-connected applications. On the other hand, it can be hard to understand what is meant by “same object” when the object is reconstituted in something that isn’t a JVM.

Java has a built-in serialization mechanism that is likely to have been partially responsible for some of Java’s early success. However, the design of this mechanism is today viewed as seriously deficient, as Brian Goetz wrote in this 2019 post, “Towards better serialization.” While the JDK team has researched ways to rehabilitate (or maybe just remove) the inbuilt platform-level serialization in future versions of Java, developers’ needs to serialize and transport objects have not gone away.

In modern Java applications, serialization is usually performed using an external library as an explicitly application-level concern, with the result being a document encoded in a widely deployed serialization format. The serialization document, of course, can be stored, retrieved, shared, and archived. A preferred format was, once upon a time, XML; in recent years, JavaScript Object Notation (JSON) has become a more popular choice.

Why you should serialize in JSON


JSON is an attractive choice for a serialization format. The following are some of the reasons:

◉ JSON is extremely simple.
◉ JSON is human-readable.
◉ JSON libraries exist for nearly every programming language.

These benefits are counterbalanced by some negatives; the biggest is that a document serialized by JSON can be quite large, which can contribute to poor performance for larger messages. Note, however, that XML can create even larger documents.

Also, JSON and Java evolved from very different programming traditions. JSON provides for a very restricted set of possible value types.

◉ Boolean
◉ Number
◉ String
◉ Array
◉ Object
◉ null

Of these, JSON’s Boolean, String, and null map fairly closely to Java’s conception of boolean, String, and null, respectively. Number is essentially Java’s double with some corner cases. Array can be thought of as essentially a Java List or ArrayList with some differences.

(The inability of JSON and JavaScript to express an integer type that corresponds to int or long turns out to cause its own headaches for JavaScript developers.)

The JSON Object, on the other hand, is problematic for Java developers due to a fundamental difference in the way that JavaScript approaches object-oriented programming (OOP) compared to how Java approaches OOP.

A class comparison. JavaScript does not natively support classes. Instead, it simulates class-like inheritance using functions. The recently added class keyword in JavaScript is effectively syntactic sugar; it offers a convenient declarative form for JavaScript classes, but the JavaScript class does not have the same semantics as Java classes.

Java’s approach to OOP treats class files as metadata to describe the fields and methods present on objects of the corresponding type. This description is completely prescriptive, as all objects of a given class type have exactly the same set of methods and fields.

Therefore, Java does not permit you to dynamically add a field or a method to a single object at runtime. If you want to define a subset of objects that have extra fields or methods, you must declare a subclass. JavaScript has no such restrictions: Methods or fields can be freely added to individual objects at any time.

JavaScript’s dynamic free-form nature is at the heart of the differences between the object models of the two languages: JavaScript’s conception of an object is most similar to that of a Map<String, Object> in Java. It is important to recognize that the type of the JavaScript value here is Object and not ?, because JavaScript objects are heterogeneous, meaning their values can have a substructure and can be of Array or Object types in their own right.

To help you navigate these difficulties, and automatically bridge the gap between Java’s static view and JavaScript’s dynamic view of the world, several libraries and projects have been developed. Their primary purpose is to handle the serialization and deserialization of Java objects to and from documents in a JSON format. In the rest of this article, I’ll focus on one of the most popular choices: Jackson.

Introducing Jackson


Jackson was first formally released in May 2009 and aims to satisfy the three major constraints of being fast, correct, and lightweight. Jackson is a mature and stable library that provides multiple different approaches to working with JSON, including using annotations for some simple use cases.

Jackson provides three core modules.

◉ Streaming (jackson-core) defines a low-level streaming API and includes JSON-specific implementations.
◉ Annotations (jackson-annotations) contains standard Jackson annotations.
◉ Databind (jackson-databind) implements data binding and object serialization.

Adding the databind module to a project also adds the streaming and annotation modules as transitive dependencies.

The examples to follow will focus on these core modules; there are also many extensions and tools for working with Jackson, which won’t be covered here.

Example 1: Simple serialization


The following code fragment from a university’s information system has a very simple class for the people in the system:

public class Person {
    private final String firstName;
    private final String lastName;
    private final int age;

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

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public int getAge() {
        return age;
    }
}

Jackson can be used to automatically serialize this class to JSON so that it can, for example, be sent over the network to another service that may or may not be implemented in Java and that can receive JSON-formatted data.

You can set up this serialization with a very simple bit of code, as follows:

var grant = new Person("Grant", "Hughes", 19);

var mapper = new ObjectMapper();
try {
    var json = mapper.writeValueAsString(grant);
    System.out.println(json);
} catch (JsonProcessingException e) {
    e.printStackTrace();
}

This code produces the following simple output:

{"firstName":"Grant","lastName":"Hughes","age":19}

The key to this code is the Jackson ObjectMapper class. This class has two minor wrinkles that you should know about.

◉ Jackson 2 supports Java 7 as the baseline version.
◉ ObjectMapper expects getter (and setter, for deserialization) methods for all fields.

The first point is not immediately relevant (it will be in the next example, which is why I’m calling it out now), but the second could represent a design constraint for designing the classes, because you may not want to have getter methods that obey the JavaBeans conventions.

It is possible to control various aspects of the serialization (or deserialization) process by enabling specific features on the ObjectMapper. For example, you could activate the indentation feature, as follows:

var mapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);

Then the output will instead look somewhat more human-readable, but without affecting its functionality.

{
  "firstName" : "Grant",
  "lastName" : "Hughes",
  "age" : 19
}

Example 2: Using Java 17 language features


This example introduces some Java 17 language features to help with the data modelling by making Person an abstract base class that prescribes its possible subclasses—in other words, a sealed class. I’ll also change from using an explicit age, and instead I’ll use a LocalDate to represent the person’s date of birth so the student’s age can be programmatically calculated by the application when needed.

public abstract sealed class Person permits Staff, Student {
    private final String firstName;
    private final String lastName;
    private final LocalDate dob;

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

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public LocalDate getDob() {
        return dob;
    }

    // ...
}

The Person class has two direct subclasses, Staff and Student.

public final class Student extends Person {
    private final LocalDate graduation;

    private Student(String firstName, String lastName, LocalDate dob, LocalDate graduation) {
        super(firstName, lastName, dob);
        this.graduation = graduation;
    }

    // Simple factory method
    public static Student of(String firstName, String lastName, LocalDate dob, LocalDate graduation) {
        return new Student(firstName, lastName, dob, graduation);
    }

    public LocalDate getGraduation() {
        return graduation;
    }

    // equals, hashcode, and toString elided
}

You can serialize with driver code, which will be slightly more complex.

var dob = LocalDate.of(2002, Month.MARCH, 17);
var graduation = LocalDate.of(2023, Month.JUNE, 5);
var grant = Student.of("Grant", "Hughes", dob, graduation);

var mapper = new ObjectMapper()
                .enable(SerializationFeature.INDENT_OUTPUT)
                .registerModule(new JavaTimeModule());

try {
    var json = mapper.writeValueAsString(grant);
    System.out.println(json);
} catch (JsonProcessingException e) {
    e.printStackTrace();
}

The code above produces the following output:

{
  "firstName" : "Grant",
  "lastName" : "Hughes",
  "dob" : [ 2002, 3, 17 ],
  "graduation" : [ 2023, 6, 5 ]
}

As mentioned earlier, Jackson still requires only Java 7 as a minimum version, and it’s geared around that version. This means that if your objects depend on Java 8 APIs directly (such as classes from java.time), the serialization must use a specific Java 8 module (JavaTimeModule). This class must be registered when the mapper is created—it is not available by default.

To handle that requirement, you will also need to add a couple of extra dependencies to the Jackson libraries’ default. Here they are for a Gradle build script (written in Kotlin).

implementation("com.fasterxml.jackson.core:jackson-databind:2.13.1")
implementation("com.fasterxml.jackson.module:jackson-modules-java8:2.13.1")
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.1")

Example 3: Using annotations


The first two examples made it look easy to use Jackson: You created an ObjectMapper object, and the code was automatically able to understand the structure of the Student object and render it into JSON.

However, in practice things are rarely this simple. Here are some real-world situations that can quickly arise when you use Jackson in actual production applications.

In some circumstances, you need to give Jackson a little help. For example, you might want or need to remap the field names from your class into different names in the serialized JSON. Fortunately, this is easy to do with annotations.

public class Person {
    @JsonProperty("first_name")
    private final String firstName;
    @JsonProperty("last_name")
    private final String lastName;
    private final int age;
    private final List<string> degrees;

    public Person(String firstName, String lastName, int age, List<string> degrees) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
        this.degrees = degrees;
    }

    // ... getters for all fields
}

Your code will produce some output that looks like the following:

{
  "age" : 19,
  "degrees" : [ "BA Maths", "PhD" ],
  "first_name" : "Grant",
  "last_name" : "Hughes"
}

Note that the field names are now different from the JSON keys and that a List of Java strings is being represented as a JSON array. This is the first usage of annotations in Jackson that you are seeing—but it won’t be the last.

Example 4: Deserialization with JSON


Everything so far has involved serialization of Java objects to JSON. What happens when you want to go the other way? Fortunately, the ObjectMapper provides a reading API as well as a writing API. Here is how the reading API works; this example also uses Java 17 text blocks, by the way.

var json = """
            {
                "firstName" : "Grant",
                "lastName" : "Hughes",
                "age" : 19
            }""";

var mapper = new ObjectMapper();
try {
    var grant = mapper.readValue(json, Person.class);
    System.out.println(grant);
} catch (JsonProcessingException e) {
    e.printStackTrace();
}

When you run this code, you’ll see some output like the following:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of 'javamag.jackson.ex5.Person' (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (String)"{
  "firstName" : "Grant",
  "lastName" : "Hughes",
  "age" : 19
}"; line: 2, column: 3]
  at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
  at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1904)

    // ...

  at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3597)
  at javamag.jackson.ex5.UniversityMain.main(UniversityMain.java:19)

What happened? Recall that ObjectMapper expects getters for serialization—and it wants them to conform to the JavaBeans get/setFoo() convention. ObjectMapper also expects an accessible default constructor, that is, one that takes no parameters.

However, your Person class has none of these things; in fact, all its fields are final. This means setter methods would be totally impossible even if you cheated and added a default constructor to make Jackson happy.

How are you going to resolve this? You certainly aren’t going to warp your application’s object model to comply with the requirements of JavaBeans merely to get serialization to work. Annotations come to the rescue again: You can modify the Person class as follows:

public class Person {
    private final String firstName;
    private final String lastName;
    private final int age;

    @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
    public Person(@JsonProperty("first_name") String firstName,
                  @JsonProperty("last_name") String lastName,
                  @JsonProperty("age") int age) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }

    @JsonProperty("first_name")
    public String firstName() {
        return firstName;
    }

    @JsonProperty("last_name")
    public String lastName() {
        return lastName;
    }

    @JsonProperty("age")
    public int age() {
        return age;
    }

    // other methods elided
}

With these hints, this piece of JSON will be correctly deserialized.

{
    "first_name" : "Grant",
    "last_name" : "Hughes",
    "age" : 19
}

The two key annotations here are

◉ @JsonCreator, which labels a constructor or factory method that will be used to create new Java objects from JSON
◉ @JsonProperty, which maps JSON field names to parameter locations for object creation or for serialization

By adding @JsonProperty to your methods, these methods will be used to provide the values for serialization. If the annotation is added to a constructor or method parameter, it marks where the value for deserialization must be applied.

These annotations allow you to write simple code that can round-trip between JSON and Java objects, as follows:

var mapper = new ObjectMapper()
                    .enable(SerializationFeature.INDENT_OUTPUT);
try {
    var grant = mapper.readValue(json, Person.class);
    System.out.println(grant);

    var parsedJson = mapper.writeValueAsString(grant);
    System.out.println(parsedJson);
} catch (JsonProcessingException e) {
    e.printStackTrace();
}

Example 5: Custom serialization


The first four examples explored two different approaches to Jackson serialization. The simplest approaches required no changes to your code but relied upon the existence of a default constructor and JavaBeans conventions. This may not be convenient for modern applications.

The second approach offered much more flexibility, but it relied upon the use of Jackson annotations, which means your code now has an explicit, direct dependency upon the Jackson libraries.

What if neither of these is an acceptable design constraint? The answer is custom serialization.

Consider the following class, which has no default constructor, immutable fields, a static factory, and Java’s record convention for getters:

public class Person {
    private final String firstName;
    private final String lastName;
    private final int age;

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

    public static Person of(String firstName, String lastName, int age) {
        return new Person(firstName, lastName, age);
    }

    public String firstName() {
        return firstName;
    }

    public String lastName() {
        return lastName;
    }

    public int age() {
        return age;
    }

}

Suppose you cannot change this code or introduce a direct coupling to Jackson. That’s a real-world constraint: You may be working with a JAR file and might not have access to the source code of this class.

Here is a solution.

public class PersonSerializer extends StdSerializer<person> {
    public PersonSerializer() {
        this(null);
    }

    public PersonSerializer(Class<person> t) {
        super(t);
    }

    @Override
    public void serialize(Person value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        gen.writeStartObject();
        gen.writeStringField("first_name", value.firstName());
        gen.writeStringField("last_name", value.lastName());
        gen.writeNumberField("age", value.age());
        gen.writeEndObject();
    }
}

Here is the driver code, with exception handling omitted to keep this example simple.

var grant = Person.of("Grant", "Hughes", 19);

var mapper = new ObjectMapper()
                    .enable(SerializationFeature.INDENT_OUTPUT);

var module = new SimpleModule();
module.addSerializer(Person.class, new PersonSerializer());
mapper.registerModule(module);

var json = mapper.writeValueAsString(grant);
System.out.println(json);

This example is very simple; in more-complex scenarios the need arises to traverse an entire object tree, rather than just handling simple string or primitive fields. Those requirements can significantly complicate the process of writing a custom serializer for your domain types.

Example 6: Java 17 records


To finish on an upbeat note: Jackson handles Java records seamlessly. The following code shows how it works; again, exception handling is omitted.

Public record Person(String firstName, String lastName, int age) {}

var grant = new Person("Grant", "Hughes", 19);

var mapper = new ObjectMapper()
                .enable(SerializationFeature.INDENT_OUTPUT);

var json = mapper.writeValueAsString(grant);
System.out.println(json);

var obj = mapper.readValue(json, Person.class);
System.out.println(obj);

This code round-trips the grant object without any problems whatsoever. Jackson’s record-handling capability, which is important for many modern applications, provides yet another great reason to upgrade your Java version and start building your domain models using records and sealed types wherever it is appropriate to do so.

Source: oracle.com

Friday, December 9, 2022

Quiz yourself: Defining the structure of a Java class

Oracle Java Certification, Java Tutorial and Materials, Java Guides, Oracle Java Certification, Oracle Java Learning

Test your knowledge of Java classes, such as their valid names, the use of variables inside a method, and the number of allowable import statements.

Which of the following statements are correct about a Java class? Choose two.

A. A Java class must have a name shown in the source code.
B. A Java class may have several local variables with the same name inside the same method.
C. A Java class may have several import statements.
D. An underscore character “_” is a valid Java class name.

Answer. Not all classes have an explicit name shown in the source code. For example, Java provides anonymous classes, such as the following:

Runnable r = new Runnable(){ public void run(){
  System.out.print("Do nothing!");
  }
};
r.run();

The run method of the Runnable interface is abstract, and yet you can see that there is a real object because you instantiated it and can invoke the run method. This shows that some concrete class, which implements the Runnable interface, exists. The variable r is a reference to an instance of that class, but the class name is not known in the source code. Therefore, option A is incorrect.

Variables are visible only within the scope in which they were defined. However, since a block bounded by curly braces defines a scope, you can create two sibling scopes inside one method. If you do this, two variables with the same name can coexist without a problem, such as in the following:

void twoVars() {
  { int i = 0; }
  { int i = 1; } // OK
}

In view of this, option B is correct.

Option C discusses multiple import statements. Having multiple import statements is not merely permitted—in most cases, it’s necessary to have many import statements to provide access to classes in different packages. It’s also typical to have multiple import statements providing access to each of several classes in the same package, rather than using wildcards.

Even repeating import statements for the same class or package is syntactically valid, though it would probably trigger a request during code review to tidy up the code.

The following is completely legal:

import java.util.*;
import java.util.*;

public class MyClass { // OK
}

By the way, if a class defines more than one package statement—whether specifying the same package name or a different package name—compilation would fail. Thus, the following would not compile:

package a.b.c;
package a.b.c; // NOT OK

public class MyClass {
}

Because option C asks only if multiple import statements are permitted, option C is correct.

As for option D, through Java 8 the single underscore character was a valid identifier and could be used as a class name, a method name, or a variable name.

In Java 8, a warning during compilation indicated that this character was reserved for future language changes. However, the warning did not prevent its use. But then, beginning with Java 9, the single underscore character was defined as a keyword and therefore is no longer valid as an identifier.

This change was described in the Java 9 summary of changes, which stated that the underscore character was not a legal name and warned that if you use the underscore character (_) as an identifier, your source code cannot be compiled.

By the way, it is still legal to use a double underscore (__) as an identifier, such as for a class name, a method name, or a variable name. You can also start a variable name with a single underscore.

public class MyClass {
    int __; // Double underscore is OK
}

Because the single underscore is a keyword and is not a legal identifier on its own any longer, option D is incorrect.

Conclusion. The correct answers are options B and C.

Source: oracle.com

Wednesday, December 7, 2022

Quiz yourself: Acceptable and unacceptable types for Java switch statements


Core Java, Oracle Java, Java Exam Prep, Java Certification, Java Tutorial and Materials, Java Quiz, Java Guides

Which switch expressions will compile successfully? Choose two.

A. var s = 1L;
switch (s) {
  case 1: {}
  default: {}
}

b. var s = 0;
switch (s>0) {
  case true: {}
  case false : {}
}

C. var s = Integer.MAX_VALUE;
switch (s+1) {
  case 0: case 1: {}; break;
  case 2: case 3, 4: {}
  case Integer.MAX_VALUE, Integer.MIN_VALUE : {}
}

D. var s = 's';
final var a = 0;
switch (s) {
  default: {break;}
  case a: {}
  case 'a': {}
}

Answer. A switch statement works with the following primitive types and their wrappers:

☉ byte
☉ short
☉ char
☉ int

In addition, you are allowed to switch on an enum or String (since Java 5). However, Boolean, long, float, and double types are prohibited. Given that a local variable declared using var takes its type from the right side of the assignment, option A attempts to switch on a long value. This is not permitted, and option A is incorrect.

As a side note, there’s a preview feature in Java 17 and Java 18 that expands the syntax, behavior, and acceptable argument types for switch significantly. Notably, you will be permitted to switch on arbitrary object types; however, at the time of writing, even though it’s permitted to switch on a wrapper such as a Double or Boolean, it remains prohibited to switch on the corresponding primitive types, and autoboxing happens. (Of course, this describes a preview feature that’s not relevant for the Java 17 exam, and it’s possible the details will change before the final release.)

In view of the previous discussion, option B—which attempts to switch on an expression of the Boolean primitive type—is also incorrect.

In option C, the switch type is presented as an Integer. This is acceptable; autounboxing will result in it being treated as an int. The arithmetic operation that adds one to the max value (2,147,483,647) will cause an overflow to the most negative value (-2,147,483,648), which is Integer.MIN_VALUE. However, that overflow does not throw an exception. Also, the question asks only if the code will compile, which it will, not if the programming logic is sound. From this, you can see option C is correct.

Option D is tricky, and two aspects demand attention.

First, one of the case expressions is a variable (specifically the int variable named a). If you ignore the preview features, Java requires that the case keyword must be followed by a constant expression, and most variables are not acceptable. However, in this example, closer inspection shows that a is, in fact, a constant expression because it’s declared as final. So, the code is acceptable from this perspective.

The second point is that you have executed the switch statement using an expression of char type, but the case expression for case a is an int. However, this is not a problem because the value of the expression a fits in the range of the char type (which is from 0 to 65,535) and the type of a is not long, float, or double—any of which would cause failure, even if they were constant expressions with a value in the acceptable range. Therefore, in this case, the expression is acceptable and option D compiles without errors. Therefore, option D is correct.

Conclusion. The correct answers are options C and D.

Source: oracle.com

Friday, December 2, 2022

Quiz yourself: What you can and can’t do with Java records

Java records are implicitly final. What does that mean in practice?


What can you declare in the body block of a Java record? Choose two.

Oracle Java, Java Exam, Java Prep, Java Preparation, Java Tutorial and Mateirals, Java Gudies, Java Materials

A. An instance variable
B. An instance method
C. An instance initialization block
D. A no-argument constructor

Answer. One of the goals of records is to approximate immutable data-carrier types. To this end, all the data elements of a record are implicitly final. Note that the record does not prevent mutation of a mutable object referred to through a final reference, however; therefore a record only approximates an immutable data carrier.

Option A is incorrect: You may not declare your instance variables in the body of a record. An example of the record syntax looks like the following:

record Car(int seats, String color) {}

Given this code, execution of new Car(5, "Red") results in an immutable object that has storage for an int value named seats and a String reference value named color. You might observe that the elements named seats and color are fields, which are commonly called instance variables.

However, for two reasons, option A is not a correct answer to this exam question. First, and most importantly, those fields are not declared in the body block of the record. Instead, they are outside the curly braces. The second, weaker, objection is that of nomenclature. Although reflection reports these as private final fields if you invoke getDeclaredFields on the Car.class object, the Java Language Specification does not refer to them this way. Rather it considers these fields to be record components.

Note that although you cannot declare instance fields in a record using the syntax used for a class, you can define class variables (that is, static variables) in a Java record.

Option B is correct: You can declare custom instance methods in a record. The record type automatically creates accessor methods for the record components, but it’s possible to define these explicitly if desired.

It’s also possible to replace the implementations of other autogenerated methods such as equals(Object o) and hashCode().

Beyond that, you can define arbitrary methods (both instance and static) according to your needs. Further, you can declare nested classes, interfaces, and other records inside a Java record.

Option C is incorrect: A record may not have an instance initialization block, but it does provide a somewhat related syntax known as a compact constructor. The compact constructor lets you interact with the initialization values prior to their being assigned to their final storage locations.

The compact constructor can also throw an exception if the construction is to be rejected.

Notably, the compact constructor cannot assign values to the final storage locations for the record components—that must be done by autogenerated code that is invoked after the compact constructor.

Option D is correct: You may declare your own constructors. A constructor with an argument type sequence matching the type sequence of the record components is called the canonical constructor. The canonical constructor is not usually coded explicitly, and if it isn’t, it will be generated automatically. The canonical constructor must assign values to the record components.

Constructors with other argument type sequences must delegate, using the this(...) delegation mechanism, in such a way that they ultimately call the canonical constructor. Since the canonical constructor must assign the record component values, noncanonical constructors cannot do this, since that would constitute multiple assignments to a final variable.

In other words, the first line of any noncanonical constructor must be an invocation of this(...), and the last element in the resulting chain must invoke the canonical constructor, as follows:

Copy code snippet
Copied to ClipboardError: Could not CopyCopied to ClipboardError: Could not Copy
record Time(int hrs, int min) {
    Time() {        // no-arg, noncanonical constructor
        this(0);    // delegates to the constructor below
    }
    Time(int hrs) { // another noncanonical constructor
                    // delegates to the autogenerated canonical constructor
        this(hrs, 0);
    }
}

Conclusion. The correct answers are options B and D.

Source: oracle.com

Wednesday, November 30, 2022

How to Perform Right-Click using Java in Selenium?

While automating a website for testing there is always required to perform some right-click or other user actions on the page.  These user actions are one of the most commonly used actions during automation, so selenium provides a way to perform these user actions by the Actions class.

How to Perform Right Click using Actions Class


When a user performs a right click using the mouse on a particular element to perform some actions is called a right click. We are daily using this user action mostly on File Explorer, For example, to rename a file or delete a file we perform right-click and select an option.

Oracle Java Certification, Oracle Java Prep, Java Tutorial and Materials, Oracle Java Material, Oracle Java Selenium

Right Click in Selenium


Let’s see how to perform the right click using Selenium. Selenium Webdriver API does not support the user’s actions like Mouse hover, right-click, context-click, and double-click. That is where the Actions class came to use, The actions provided by this class are performed by an API called Advanced user interaction in selenium webdriver.

Action class present in the package,

“org.openqa.selenium.interactions package”

Let’s see how to use the Actions class to Right Click an element:

Instantiate an object for the Actions class 

Actions action = new Actions(driver);

After creating the object we have to locate the web element

WebElement element=driver.findElement(locator);

Using the “ContextClick() method” from the Actions class to perform the Right click. Context Click methods navigate the mouse pointer to the middle of the web Element and then perform the right-click action in that web element.

action.contextClick(webElement).perform();

Example


In this example, we are navigating to the URL “https://demoqa.com/buttons” and performing the Right click on the “Right click” button. 

public class Java {

public void oraclejavacertified()
{

ChromeDriver driver = new ChromeDriver();
driver.manage().window().maximize();
driver.get("https://demoqa.com/buttons");
WebElement element
= driver.findElement(By.id("rightClickBtn"));
Actions action = new Actions(driver);
action.contextClick(element).perform();

Thread.sleep(5000);
driver.close();
}

Code Explanation


Initially, we opened the browser and navigated to the URL

ChromeDriver driver = new ChromeDriver();
driver.manage().window().maximize();
driver.get(“https://demoqa.com/buttons”);

After that, we locate the web element where we have to perform the “Right Click”. Then, We initialize the Action class and performed “Right click” on the web element.

 Actions action=new Actions(driver);
 action.contextClick(element).perform();

Output

    
Right-click is performed and the result will be displayed.

Oracle Java Certification, Oracle Java Prep, Java Tutorial and Materials, Oracle Java Material, Oracle Java Selenium

Source: geeksforgeeks.org

Monday, November 28, 2022

Java Modules – Service Interface Module

Java Modules, Oracle Java, Oracle Java Career, Java Skill, Java Jobs, Java Tutorial and Material, Java Certification, Java Interface

Service Provider Interface, a feature of Java 6, makes it possible to find and load implementations that adhere to a specified interface. In this article, we’ll introduce Java SPI’s components and demonstrate how to use it in a real-world scenario. a well-known collection of programming classes and interfaces that give users access to a particular feature or functionality of an application. Applications are now more extendable thanks to the introduction of the Service Provider Interface. It provides us with a way to improve particular product features without changing the main application. All we have to do is plug in a new implementation of the service that adheres to the established requirements. The program will load the new performance and use it by means of the SPI protocol.


◉ Service Provider Interface: Service Provider Interface is referred to as SPI. It is a subset of everything that may be API-specific in circumstances where a library offers classes that an application (or API library) calls and that typically alter what the application is able to do.

◉ Service Provider: A particular service implementation is referred to as a “provider” as well. By putting the provider configuration file in the resources directory META-INF/services, it can be located. It must be accessible through the classpath of the application.

◉ ServiceLoader: A class that implements the well-known interface or subclasses it is referred to as a service provider (or simply a provider). When an application chooses, a ServiceLoader is an object that finds and loads service providers deployed in the run time environment.

A particular application of the SPI. One or more concrete classes that implement or extend the service type are present in the service provider. A provider configuration file that we place in the resource directory META-INF/services allows us to configure and identify a service provider. The fully-qualified name of the SPI is contained in both the file name and its content, which is the name of the SPI implementation. The Service Provider is installed using extensions, a jar file that is added to the application classpath, the classpath for Java extensions, or a custom classpath. 

Now Let’s see the Example.

Example


In this example, we will implement a service interface module in java using the classic classics library module. this program implementation will have access to the getBook() method.

<!-- We're including all the
dependencies here in this program -->
<dependency>
<groupId>org.library</groupId>
<artifactId>library-service-provider</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

Then we will create a class that will implement the SPI library.

package org.library;

// Inheriting the class
public class ClassicsLibrary implements Library {

public static final String Classic_Library
= "Classic_Example";
private final Map<String, Book> books;

// ClassicsLibrary() method declaration
public ClassicsLibrary()
{
books = new TreeMap<>();
Book Example_1
= new Book("It's 2022", "Mr. Sinha", "Des");
Book Example_2 = new Book("It's EG2 book Name",
"Mis Sinha", "Des");

books.put("It's 2022", Example_1);
books.put("It's EG2 book Name", Example_2);
}

@Override public String getCategory()
{
return Classic_Library;
}

@Override public Book getBook(String name)
{
return books.get(name);
}
}

It should be evident how to use the Java SPI to develop readily expandable or replacement modules now that we have investigated the mechanism through a set of stated steps. Although the Yahoo exchange rate service was used in our example to demonstrate the capability of connecting to other external APIs, production systems don’t need to rely on third-party APIs to develop fantastic SPI applications.

Source: geeksforgeeks.org