Friday, September 29, 2023

Quiz yourself: Deserializing objects that have a nonserializable parent

Quiz Yourself, Oracle Java, Core Java, Java Prep, Java Preparation, Java Certification, Java Career, Java Tutorial and Materials, Java Guides

What’s correct and what’s not correct about the Java deserialization process?


You are working to enhance a legacy application, in particular to add serialization support and add more constraints to new business objects. The legacy application class looks like this.

public class Person {
  private String name = null;
  public Person() {}
  public Person(String s) {
    name = s;
  }
}

You’ve also added a new application class.

public class EnhancedPerson extends Person implements Serializable {
  public EnhancedPerson(String s) {
    super(s);
    if (s == null || s.length() == 0) {
      throw new IllegalArgumentException("Invalid name");
    }
  }
}

Which statement is correct? Choose one.

A. The EnhancedPerson class may not participate in serialization because its superclass is not serializable.
B. The EnhancedPerson class may not participate in serialization because it does not have a zero-argument constructor.
C. The EnhancedPerson class can be serialized but cannot be deserialized.
D. Immediately after deserialization, the name field of an EnhancedPerson will have a null value.
E. The EnhancedPerson class will always throw IllegalArgumentException during deserialization.

Answer. This question investigates the deserialization process of an object that has a nonserializable parent type. Of course, every object has a nonserializable parent because, even if nothing else were true, java.lang.Object itself falls into this category.

This first observation tells you that option A must be incorrect because a nonserializable parent type is inevitable and, therefore, cannot possibly prevent serialization and deserialization.

Two more rules regarding the serialization system are relevant to answering this question.

  • When a serializable object is deserialized, the nonserializable parent aspects are initialized by calling an accessible zero-argument constructor in the immediate parent that’s not serializable.
  • Except for record types, deserialization does not use any of the constructor or initialization code for the elements of that object hierarchy that are serializable.

From those two points, you can see that option B is incorrect.

Option C is also incorrect because nothing in the code prevents deserialization. If the zero-argument constructor of Person were private, or if it did not exist, this option would be correct.

Option D is correct because the name field belongs to the Person aspect of the EnhancedPerson object. Such fields are not part of the serialized information. As noted earlier, when the Person instance is re-created, this is done by calling the zero-argument constructor of Person. Because of this, the name field will be initialized to null. Of course, this would also be the case if the assignment of null were not present in the code, because the memory allocated for an object is always zeroed before it becomes available for use as the new object.

Regarding why option E is incorrect, recall that the deserialization process for (nonrecord) classes does not call any constructor in the Serializable aspects of the object. This means that the code in the EnhancedPerson constructor that validates the supplied name will not be called; therefore, no exception can be thrown.

This discussion raises questions. In the current design, deserialization creates an EnhancedPerson object with a null name field. The validation in the constructor is clearly intended to make this impossible. There would be aspects to address in restoring this integrity.

One aspect would be to ensure that the name field is immutable (the Person class currently has no setters and name is private, but the class is clearly a skeleton because it has no usable methods). Alternatively, you could ensure that all changes are controlled by the EnhancedPerson in a way that keeps it valid.

The second aspect, which is more relevant to this question, would be to ensure that any EnhancedPerson object deserialized from a data stream conforms to the validity rules. This can be accomplished by providing a private readObject method. This method allows you to take control of the deserialization process. In the following example, the object is read from the stream using the default mechanism, but then it’s checked to determine if it is valid. If it’s not valid, the exception that’s thrown will cause the deserialization to be abandoned.

private void readObject(ObjectInputStream ois) throws
  IOException,
  ClassNotFoundException {
  ois.defaultReadObject();
  if (name == null || name.length() == 0) {
    throw new InvalidObjectException("Invalid name");
  }
}

Conclusion. The correct answer is option D.

Source: oracle.com

Wednesday, September 27, 2023

Quiz yourself: Serializing a primitive with ObjectOutputStream

Quiz Yourself, Oracle Java Certification, Java Guides, Java Learning, Java Certification Preparation, Java Preparation, Java Prep Exam

Primitives? Objects? What should you do?


You need to serialize a long primitive value, and you have been given the following code:

long l = 5L;
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filename))) {
  ... //
}

Which statement is true? Choose one.

A. The code must box the primitive using oos.writeObject(Long.valueOf(l)).
B. The primitive must be included in the outer Java class as an instance variable to be serialized.
C. The serialization should be implemented as oos.writeObject(l).
D. The serialization should be implemented as oos.writeLong(l).
E. The serialization must delegate to the DataOutput class for writing primitives.

Answer. Java serialization provides a way to represent a graph of objects as a byte sequence. This mechanism also supports primitive data directly, as part of objects. Primitive wrapper classes also implement the Serializable interface and can be serialized too. Commonly, the byte sequence that results from serialization is written to disk for long-term storage or is transmitted across a network.

In most cases, you will use the class ObjectOutputStream to create the serialized byte stream. This class provides the writeObject method proposed in option C, and that method readily handles serializing an entire graph of objects. The result can be transparently restored using the ObjectInputStream class. Note, however, that the argument to the writeObject method is an object, not a primitive.

The previous discussion tells you something about option C: If it’s used, autoboxing would occur and you would not serialize the primitive value. Instead, you would have a serialized representation of the wrapper that was created. At this point in analyzing the exam question, it’s probably too early to reject this option, but you must decide whether any other answer is a better match with the proposition of the question—which does, after all, specifically mention that you are serializing a primitive value.

It turns out that ObjectOutputStream implements the java.io.DataOutput interface. That interface defines writeXXX methods for all primitives. As a side note, DataOutput is also implemented by the class java.io.DataOutputStream, but although that class works with primitives and strings, it cannot perform serialization. This capability is described in option D, and it will allow you to use the oos object to serialize the primitive directly. From this you can determine that option D is correct. It’s definitely better than option C, and you can now confidently reject option C as incorrect.

Although you should feel confident in the correctness of option D, you should still verify that the other options are incorrect. In an exam, you might discover another option that seems correct, which would cause you to revisit your reasoning. But if you’re tight on time, you might go with the first answer that appears correct.

Option A is incorrect: The ObjectOutputStream is able to serialize primitives directly, which means that boxing is not necessary. Of course, if your application calls for it, you can box or autobox the primitive, but it’s not necessary. Further, the result will take substantially more space in the resulting byte sequence.

Option B is also incorrect for essentially for the same reason as with options A and C. Certainly primitives that are members of objects are handled correctly, but it’s not necessary to wrap a primitive in such an object just to get it out into the byte sequence.

Option E is incorrect, because, as discussed earlier, java.io.DataOutput is an interface, not a class, as is suggested in the stem. The interface declares the signatures of various methods, including the writeLong method you will use, but writeLong is (and, in fact, all the methods of this interface are) abstract. The implementation is provided by the java.io.ObjectOutputStream class; therefore, delegation in the code is not necessary or possible.

Conclusion. The correct answer is option D.

Source: oracle.com

Friday, September 15, 2023

Quiz yourself: Deserializing objects with readObject

Quiz Yourself, Oracle Java Career, Oracle Java Skill, Oracle Java Jobs, Oracle Java Prep, Oracle Java Preparation, Oracle Java Object

You should know how the readObject method works—and when it won’t compile.

Given the following Person record

record Person(String name) implements Serializable {}

and the following method fragment

try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(filename))) {
    ... // code here
    System.out.println(person.name());
}

Assume that the try block is completed with necessary catch blocks and the file contains a serialized Person and opens correctly.

The code from which option, when placed where the comment is, properly deserializes the object and allows the rest of the code to work? Choose one.

A. var person = (Person) null;
if (in.readObject() instanceof Person p) {
  person = p;
}
B. var person = in.readObject();

C. Person person = null;
if (in.readObject() instanceof Person) {
  person = in.readObject();
}

D. var person = null;
Object o = in.readObject();
if (o instanceof Person) {
  person = (Person) o;
}

Answer. We will skip over option A for the moment.

Option B would read the serialized object from the file, but the return type of the readObject method is declared as Object; therefore, var will infer the type of the person variable to be Object too. This means that person.name() will not compile. From this you can see that option B is incorrect.

Option C is incorrect for two reasons. The semantics of the code would cause the input stream to be read twice, and the result of the first reading operation would be lost. However, there is a more severe problem; as already mentioned, the return type of readObject is Object, and the following assignment to the person variable (which is declared explicitly as being of type Person in this option) would fail unless an explicit cast were added:

person = in.readObject(); // assignment fails!

The following cast would fix the problem:

person = (Person)in.readObject(); // this could work

Option D is also incorrect. When var is used to declare a local variable (other than a lambda formal parameter), the compiler must be able to decide, unambiguously, the intended type of the variable based on the expression that is assigned for initialization. The null value does not provide type information—it is assignment-compatible with any reference type. So, compilation would fail.

Changing the declaration to the following would allow option D to work:

var person = (Person) null;

Option A is correct. It uses the newer “pattern matching for instanceof” feature that was added (after several previews) in Java 16 as JEP 394. The effect is that if the deserialized object is, in fact, assignment-compatible with the Person type, the variable p is declared and initialized with the reference to that object. The scope of p is such that it’s usable only in the parts of the code where it has definitely been initialized. For example, if there were an else clause on the if statement, p would be out of scope in that else clause.

Conclusion. The correct answer is option A.

Source: oracle.com

Monday, September 11, 2023

Java Card 3.1: Security Services

Java Card Technology, Core Java, Oracle Java Certification, Java Prep, Java Preparation, Oracle Java Tutorial and Materials, Oracle Java Guides

A key goal of version 3.1 is to ensure the availability of security services on a large range of secure hardware, including smartcards, embedded chips, secure enclaves within microprocessor units (MPUs) and microcontroller units (MCUs), and removable SIMs. It was designed to support the growth of existing Java Card markets, such as payment, identity, and connectivity markets, while enabling new IoT use cases with dedicated features. This blog entry covers those features.

Security services in Java Card 3.1 include the Certificate API, the Key Derivation API, the Monotonic Counter API, and the System Time API. Let’s look at these in more detail.

Certificate API. Cryptographic certificates are critical for security and serve as a basis in a public key infrastructure (PKI) to establish trust between different entities. A notable example of a protocol using cryptographic certificates is the Transport Layer Security (TLS) protocol. Based on certificate chains, a client (such as an IoT gateway) and a server (for example, an IoT cloud service) can authenticate each other.

The javacardx.security.cert package is an efficient way to manage cryptographic certificates such as X.509 certificates for memory- and resource-constrained devices.

With Java Card’s Certificate API, it is possible to verify a certificate signature, select and check some of its fields and extensions, and access its public key—without needing to create a dedicated certificate object that is potentially useless in the future. You can also build a certificate object (for example, for root certificates) that will be reused later, while deciding on fields and extensions that need to be associated with this certificate object and storing only useful components of the certificate.

With these mechanisms, an application has an efficient way to verify a certificate chain, check sensitive certificate fields, and keep track of trusted public keys.

Key Derivation API. Pseudorandom functions (PRFs) and key derivation functions (KDFs) are widely used in cryptography to derive sensitive data such as a secret key. They make it possible to stretch a secret or to derive multiple keys from it.

A typical usage is the derivation of a password to store a derived value without needing to store the initial password value. Another common example is the derivation of the shared secret established by a key-agreement operation in Diffie-Hellman (DH) or Elliptic-Curve Diffie Hellman (ECDH) key exchange. Another example is the TLS handshake protocol, which uses a PRF applied to a shared secret in between a client and a server to generate the cryptographic block material used during a TLS session between the two peers.

Java Card 3.1 introduces the javacardx.security.derive package. Its class DerivationFunction permits the management of both PRF and KDF algorithms, and it is easily extensible. Currently, eight algorithms are proposed that enable support for the International Civil Aviation Organization (ICAO) or TLS protocols, among others.

In addition, the Key Derivation API guarantees both the security of the derivation keys and the derived keys by encapsulating them into trusted objects.

Monotonic Counter API. To prevent replay attacks, numerous security protocols use monotonic counters, which are counters whose value can only increase. Once the value of a monotonic counter has been used, the counter is incremented (typically by 1). Thus, if a counter value has been attached to a given protocol payload at a certain time, it is guaranteed that the same counter value cannot be reused and attached to the same protocol payload later. This allows a third party consuming the protocol payload to know whether it has already been used by checking the counter value.

Device attestation (also known as remote attestation) is an example of a payload that needs to be protected against replay attacks. A remote attestation is a signature of software measurements running on a given device, and the attestation is sent to a third party. The third party can check whether a device is running unaltered software and can make sure the attestation is current and not replayed from the past.

External secure storage is another example requiring a monotonic counter. DRM licenses or the number of PIN entry tries are typical sensitive data protected by a Java Card secure element. In some hardware architectures, like the ones with an integrated secure element, such sensitive data might be stored in the memory flash of the host device; that is, in storage external to the secure element hardware itself. Thus, untrusted and rogue applications from the device host might be able to save and restore later such sensitive data. In the case of a DRM license, this risk would mean that access to a content item is granted an unlimited number of times instead of the initial limited times granted originally. Hence, in addition to integrity and confidentiality, the secure element must guarantee an anti-replay protection to sensitive data stored in external secure storage.

The javacardx.security.util package and its MonotonicCounter class enable the creation and management of multiple monotonic counters of up to 64 bits each. The Monotonic Counter API guarantees the atomicity of the update of the counter value.

System Time API. Time stamping and time interval calculation are important security operations. Time stamps enable you to record or check the time at which an event occurred. Estimating a time interval allows you to limit the duration of a transaction, for instance.

Java Card 3.1 introduces the package javacardx.framework.time, which has two classes:

◉ SysTime serves to retrieve the uptime; that is, the time elapsed since system boot. It does not require an internal clock.
◉ TimeDuration represents a time duration with microsecond resolution. Several operations, such as comparisons and conversions as well as plus and minus operations, are supported.

Java Card’s System Time API can support a variety of use cases related to device security. For example, consider an IoT device managing a temperature sensor in the chemical industry. This monitoring system is critical and needs to react to unexpected temperature variations. With the new I/O mechanism introduced in Java Card 3.1 and the System Time API, an application has the ability to retrieve a temperature value securely and to assess the elapsed time since the beginning of the measurement. If the time is too short or too long compared with the average expected value, this is reported to the monitoring system, which will trigger corrective operations such as changing the sensor or checking for a corruption of the IoT device software.

Source: oracle.com

Friday, September 8, 2023

Quiz yourself: Collectors, comparators, and type inferencing in Java

Quiz Yourself, Oracle Java Career, Oracle Java Skills, Oracle Java Jobs, Oracle Java Prep, Oracle Java Preparation, Oracle Java Preparation


Your colleague is working on an application that must find a most-frequently used word in a Stream<String>, and each element of that stream is a single word. The stream is provided by the reference strm.

Which of these pipeline expressions can perform this task? Choose two.

A.

strm.collect(Collectors.groupingBy(Function.identity(),
Collectors.counting())).entrySet().stream().sorted((e1,
e2)-> e2.getValue().compareTo(e1.getValue())).findFirst()

B.

strm.collect(Collectors.groupingBy((String s) -> s, 
Collectors.counting())).entrySet().stream().sorted(
Map.Entry.comparingByValue()).findFirst()

C.

strm.collect(Collectors.groupingBy(a -> a,
Collectors.counting())).entrySet().stream().sorted(
Map.Entry::comparingByValue).findFirst()

D. 

strm.collect(Collectors.groupingBy(Function.identity(), 
Collectors.counting())).entrySet().stream().sorted((e1, 
e2)-> e2.getValue() - e1.getValue()).findFirst()

E.

strm.collect(Collectors.groupingBy(___ -> ___, 
Collectors.counting())).entrySet().stream().max(Comparator.
comparing(e -> e.getValue()))

Answer. This question investigates aspects of the Collectors utilities, ordering using a Comparator, type conversion rules, and type inferencing in Java’s generics system.

All but one of the question’s code fragments take the following four-step approach to the problem, with variations in the implementation details:

Step 1. Take each word and use the groupingBy collector to build a map in which each key is a word from the stream, and the value accumulates the number of occurrences of the word in the stream. The groupingBy method is a factory that builds a collector, and in the form used here it takes two arguments. The first derives a key for the resulting map from the object in the stream. In this case, the object in the stream is the word you want to use as the key, so no change is necessary. The second argument is Collectors.counting(), which is used as a downstream collector that modifies the value stored against the key in the map to be a count of the number of times the key has been seen, instead of being a list of the objects that produced that key.

Step 2. The code then extracts a stream from that map. The Map interface cannot directly provide a Stream, but it provides access to a Set<Map.Entry> using the entrySet method. A Map.Entry<K, V> is a single key-value pair (a tuple of K and V, essentially, although Java does not provide tuples at a language syntax level). A Set does allow drawing a Stream directly, which is the next step.

Step 3. Sort the stream of entries. This must be done in descending order of the value part of the entry since that’s the count of occurrences of the word represented in the key.

Step 4. The reason that descending order is essential is that the final step is to pull the first entry object from the resulting stream using a findFirst method. If the stream were sorted in ascending order, you’d get the least-used word rather than the most-used one. It’s worth noting that if two or more words tie for top place in usage, you’ll get one of them with no control over which one you get. But you can ignore that possibility in this question; notice the specification says, “a most-frequently used word,” rather than “the most-frequently used word.” Therefore, you don’t need to worry about a tie.

Option A is a correct implementation of this approach. The first argument to the groupingBy factory method should be a function that takes the stream object and returns the key. As noted, in this situation the key is the same as the stream object, and Function.identity() is a factory for a Function object that returns its own argument unchanged. The second argument is the counting factory, and that’s exactly what was described above. Next, the sorting is performed using Comparator explicitly coded as a lambda expression. The effect is to compare the value of the two entry objects, but because the code is written as e2 … compareTo … e1, the ordering will be reversed and, therefore, descending.

Option B is incorrect. Although it is syntactically valid, the stream is sorted in ascending order; therefore, it will return an entry with a least-frequently used word. You could correct this code by reversing the ordering of the comparator, as follows:

strm.collect(Collectors.groupingBy((String s) -> s, 
Collectors.counting())).entrySet().stream().sorted(Map.Entry.<String, 
Long>comparingByValue().reversed()).findAny();

Notice the use of <String, Long> before comparingByValue().reversed(). The code fails to compile without this because the Java compiler cannot infer the generic type parameters in this situation. Therefore, this syntax is used to specify the types explicitly.

Another difference in the approach taken by option B, which is valid in isolation, is the replacement of Function.identity() with an explicit lambda: (String s) -> s. This is valid, and in this code has the same effect of returning its argument unchanged. The argument type is redundant, but it is valid because the objects in the stream are of String type.

Option C also changes Function.identity() to an explicit lambda: a -> a. As with option B, this has the same effect and is not a problem.

Looking at the second argument to groupingBy—the downstream collector—you know this must be an object of Collector type. However, Map.Entry::comparingByValue is a method reference; if the code were compilable in this location, it would create an object equivalent to a lambda expression such as x -> Map.Entry.comparingByValue(x). That would be a Function that returns a Comparator. However, Function is not valid at this point, because the code needs an actual Comparator object. From this you can see that option C is incorrect.

Option D is also incorrect. As already mentioned, Collectors.counting() returns a collector that counts the number of occurrences of elements. The total is accumulated as a Long. Later in the hand-coded comparator, Long is subtracted from Long, and this gives a Long result (which could, under appropriate conditions, be autounboxed to a long primitive). However, the return type of the comparator’s compare method must be int, and it’s not legal to convert a Long (or even a long) to an int without an explicit cast. The following code includes the necessary cast and would work correctly:

(e1, e2)-> (int)(e2.getValue() - e1.getValue())

Option E changes two things. First, it uses an explicit lambda instead of Function.identity(). You saw this in two previous examples, but here the variable name is odd. It’s ___ (which is a triple underscore) rather than something more normal such as s or a. It turns out that this is actually a valid identifier in Java. A single underscore is a reserved keyword (since Java 9), but a leading underscore followed by more characters (even if they’re just more underscores) or an underscore embedded in the middle of a name is legal. It’s worth noting that using a triple underscore as a variable name would likely get some raised eyebrows in a code review, so don’t tell anyone we said it’s a good idea. We definitely are not suggesting that it’s anything other than a curiosity!

Another difference in this example is the use of the max terminal operation rather than ordering followed by findFirst. This works correctly and might be more efficient because it doesn’t require the processing of the second stream to build a structure containing references to all the elements; instead, only a reference to the largest element so far needs to be kept. In any case, option E is correct.

Here are three interesting side notes.

First: You can read about the difference between Function.identity() and a -> a in our earlier quiz “Quiz yourself: Mixing and matching Java primitives with generics in a stream.”

Second: In the case of English, the most-frequently used word is generally “the,” but in any given body of text, that might not be the case. Of course, this quiz’s code could be used to analyze text in any language.

Third: The stem of the question mentions that the items listed are expressions. As such they’re not complete Java code but must be used in some larger context, perhaps to provide a value to be assigned to a variable or as an argument to a method invocation. However, a general guide for the exam is that if code is valid as shown but incomplete, you should assume there’s enough supporting code around it to allow it to work if it can do so; you’re being asked solely about the validity of what’s shown, not about what you can’t see. The Java SE 17 Developer exam (1Z0-829) has a section called “Assume the following” under the expandable tab “Review exam topics.” Among other things, it specifies the following:

If sample code does not include package or import statements, and the question does not explicitly refer to these missing statements, then assume that all sample code is in the same package, or import statements exist to support them.

Conclusion. The correct answers are options A and E.

Source: oracle.com