gson supports records

I like using records in Java and getting rid of the boilerplate on my immutable objects. I also like using gson (google’s serialization/deserialization library) for my lightweight JSON needs. All I need is an annotation to use a different field type. (For complex parsing I use Jackson)

Suppose I want parse this

var json = """

For example before records, I would write:

class Name {
	 private String first;
	 private String last;
     @SerializedName("birth_year") int birthYear;

     // boilerplate methods

I needed to use my IDE to generate a constructor, getters, and a toString(). And additionally, equals/hashCode if needed for that class.

In Java 17, I switched to records. I didn’t realize I could use them with gson annotations until recently. Turns out all I need to write is:

record Name(String first, 
   String last, 
   @SerializedName("birth_year") int birthYear) { }

The parsing code remains the same

var gson = new Gson();
var name = gson.fromJson(json, Name.class);

ChatGPT for education – is it like a calculator?

At the NYC FRC (FIRST Robotics Challenge) local kickoff, there was a speaker from Columbia about AI. The target audience was high school students. He said two things that stuck with me. First was:

Self awareness is the ability to imagine yourself in the future; the farther in the future, the more self aware

He also noted that his dog can imagine himself about a minute in the future. Like eating the food about to come. Humans can imagine further out of course.

The other was about AI being like a calculator. I like that analogy. It shows that using ChatGPT isn’t a replacement for learning how to write/code/etc. We don’t let kids use a calculator on tests until they already know how to add. And you don’t want to have to go to a calculator or pull out your phone to add 5 + 8!

toList() vs collect(Collectors.toList())

I had some extra time this week so went through a bunch of Sonar findings. One was interesting – in Java 17 you can use .toList() instead of .collect(Collectors.toList()) on a stream.

[Yes, I know this was introduced in Java 16. I live in a world where only LTS releases matter]

Cool. I can fix a lot of these without thinking. It’s a search and replace on the project level after all. I then ran the JUnit regression tests and got failures. That was puzzling to me because I’ve been using .toList() in code I write for a good while without incident.

After looking into it, I found the problem. .toList() guarantees the returned List is immutable. However, Collectors.toList() makes no promises about immutability. The result might be immutable. Or you can change it freely. Surprise?

That’s according to the spec. On the JDK I’m using (and Jenkins is using), Collectors.toList() was returning an ArrayList. So people were treating the returned List as mutable and it was working. I added a bunch of “let’s make this explicitly mutable” and then I was able to commit.

Here’s an example that illustrates the diference

import java.util.*;

public class PlayTest {

	public static void main(String[] args) {

		var list = List.of("a", "b", "c");
		var collectorReturned = collector(list);
		var toListReturned = toList(list);
		System.out.println(collectorReturned.getClass());  // ArrayList (but doesn't have to be)
		System.out.println(toListReturned.getClass());  // class java.util.ImmutableCollections$ListN
		System.out.println(collectorReturned);  // [bb, cc, x]
		toListReturned.add("x");  // throws UnsupportedOperationException


	private static List<String> toList(List<String> list) {
				.filter(s -> ! s.equals("a"))
				.map(s -> s + s)

	private static List<String> collector(List<String> list) {
				.filter(s -> ! s.equals("a"))
				.map(s -> s + s)

Collectors.toList() also makes no promises about serializablity or thread safety but I wasn’t expecting it to.