Skip to content

Auto detect records for Jackson serialization#993

Merged
electrum merged 1 commit into
airlift:masterfrom
Randgalt:jordanz/auto-detect-records-for-jackson
Jun 13, 2022
Merged

Auto detect records for Jackson serialization#993
electrum merged 1 commit into
airlift:masterfrom
Randgalt:jordanz/auto-detect-records-for-jackson

Conversation

@Randgalt
Copy link
Copy Markdown
Contributor

@Randgalt Randgalt commented Jun 10, 2022

Currently, record serialization requires annotating records with
@JsonAutoDetect(getterVisibility = PUBLIC_ONLY). This is a nuisance
and can be hard to debug when it's forgotten (Jackson serializes
to an empty object when it's missing).

Add a Jackson module that auto-detects Records and sets
the visibility to match the annotation. Note: Airlift is
currently at Java 11 so record detection is not ideal (though it
mimics what the JDK does). Once Airlift is at Java 17 it can
be updated and a test can be added.

Note: I tested this in Java 17 project independently to verify that it works.

@Randgalt
Copy link
Copy Markdown
Contributor Author

cc @electrum, @dain and/or @martint

@Randgalt Randgalt force-pushed the jordanz/auto-detect-records-for-jackson branch 2 times, most recently from 9c6748e to 7733c63 Compare June 10, 2022 12:47
@findepi
Copy link
Copy Markdown
Contributor

findepi commented Jun 10, 2022

Note: I tested this in Java 17 project independently to verify that it works.

Would it make sense to have a Java 17-based test module to verify Java 17-related Airlift behavior?

@Randgalt
Copy link
Copy Markdown
Contributor Author

Note: I tested this in Java 17 project independently to verify that it works.

Would it make sense to have a Java 17-based test module to verify Java 17-related Airlift behavior?

Yes - I think it does. However, I would do it as a separate PR. It will make the CI more complicated.

@Randgalt Randgalt force-pushed the jordanz/auto-detect-records-for-jackson branch from 7733c63 to c8e8355 Compare June 10, 2022 14:11
private static boolean isRecord(Class<?> clazz)
{
Class<?> superclass = (clazz != null) ? clazz.getSuperclass() : null;
return (superclass != null) && superclass.getName().equals("java.lang.Record") && ((clazz.getModifiers() & Modifier.FINAL) != 0);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think Modifier.isFinal(clazz.getModifiers()) is the preferred way

Comment thread json/src/main/java/io/airlift/json/RecordAutoDetectModule.java Outdated
@Randgalt Randgalt force-pushed the jordanz/auto-detect-records-for-jackson branch 2 times, most recently from d6bb735 to 358d307 Compare June 10, 2022 23:40
@Randgalt Randgalt force-pushed the jordanz/auto-detect-records-for-jackson branch from 358d307 to 5d445a3 Compare June 13, 2022 18:30
public class RecordAutoDetectModule
extends SimpleModule
{
private static final Optional<MethodHandle> isRecord;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make uppercase since this is a constant

public Introspector()
{
recordVisibilityChecker = VisibilityChecker.Std.defaultInstance()
.withGetterVisibility(JsonAutoDetect.Visibility.PUBLIC_ONLY)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it intended that this is duplicated below?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

derp


public Introspector()
{
recordVisibilityChecker = VisibilityChecker.Std.defaultInstance()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make this a constant?

{
try {
// TODO replace with real call to isRecord() when Airlift is on Java 14+
return (Boolean) methodHandle.invoke(ac.getRawType());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be able to use invokeExact() here and cast to (boolean) to avoid boxing.

try {
//noinspection JavaLangInvokeHandleSignature
methodHandle = MethodHandles.lookup()
.findVirtual(Class.class, "isRecord", methodType(Boolean.TYPE));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One more nit: use boolean.class here for the primitive class reference

Currently, record serialization requires annotating records with
`@JsonAutoDetect(getterVisibility = PUBLIC_ONLY)`. This is a nuisance
and can be hard to debug when it's forgotten (Jackson serializes
to an empty object when it's missing).

Add a Jackson module that auto-detects Records and sets
the visibility to match the annotation. Note: Airlift is
currently at Java 11 so record detection is not ideal (though it
mimics what the JDK does). Once Airlift is at Java 17 it can
be updated and a test can be added.
@Randgalt Randgalt force-pushed the jordanz/auto-detect-records-for-jackson branch from 5d445a3 to d6dc459 Compare June 13, 2022 19:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants