Skip to content

#3305 - fix default CharSequence serialization #3332

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,8 @@ protected List<BeanPropertyWriter> findBeanProperties(SerializerProvider prov,
protected List<BeanPropertyWriter> filterBeanProperties(SerializationConfig config,
BeanDescription beanDesc, List<BeanPropertyWriter> props)
{
removeDefaultProperties(props);

// 01-May-2016, tatu: Which base type to use here gets tricky, since
// it may often make most sense to use general type for overrides,
// but what we have here may be more specific impl type. But for now
Expand Down Expand Up @@ -767,6 +769,28 @@ protected void removeSetterlessGetters(SerializationConfig config, BeanDescripti
}
}

/**
* Helper method that will remove all properties that are added by default JDK methods,
* e.g. java.lang.CharSequence.isEmpty() (since JDK 15).
*/
private void removeDefaultProperties(List<BeanPropertyWriter> properties)
Copy link
Author

Choose a reason for hiding this comment

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

I'm not quite sure about the policy with new protected methods, so I minimized the visibility for the first iteration

{
Iterator<BeanPropertyWriter> it = properties.iterator();
while (it.hasNext()) {
BeanPropertyWriter writer = it.next();

AnnotatedMember member = writer.getMember();
if (member != null) {
Class<?> declaringClass = member.getDeclaringClass();

if (declaringClass == CharSequence.class) {
// #3331 JDK 15 defines CharSequence.isEmpty() method that is treated as property
it.remove();
}
}
}
}

/**
* Helper method called to ensure that we do not have "duplicate" type ids.
* Added to resolve [databind#222]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.fasterxml.jackson.databind.ser.jdk;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class CharSequenceSerializationTest {

private static final String APP_ID = "3074457345618296002";

@Test
public void objectMapperShouldSerializeAsJsonStringValue() throws Exception {
ObjectMapper objectMapper = new ObjectMapper();

AppId appId = AppId.valueOf(APP_ID);

String serialized = objectMapper.writeValueAsString(appId);

//Without a fix fails on JDK17 with
//org.junit.ComparisonFailure:
//Expected :{"empty":false}
//Actual :"3074457345618296002"
assertEquals(serialized, "\"" + APP_ID + "\"");
}

public static final class AppId implements CharSequence {

private final long value;

public AppId(long value) throws IllegalArgumentException {
this.value = value;
}

public static AppId valueOf(String value) throws IllegalArgumentException {
if (value == null) {
throw new IllegalArgumentException("value is null");
}
return new AppId(Long.parseLong(value));
}

@Override
public int length() {
return toString().length();
}

@Override
public char charAt(int index) {
return toString().charAt(index);
}

@Override
public CharSequence subSequence(int start, int end) {
return toString().subSequence(start, end);
}

// pay attention: no @JsonValue here
@Override
public String toString() {
return Long.toString(value);
}
}

}