Skip to content
Merged
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 @@ -1279,6 +1279,11 @@ boolean record = BeanUtils.isRecord(objectClass);
String[] parameterNames = beanInfo.createParameterNames;
if (record && parameterNames == null) {
parameterNames = BeanUtils.getRecordFieldNames(objectClass);
if (beanInfo.namingStrategy != null && parameterNames != null) {
for (int i = 0; i < parameterNames.length; i++) {
parameterNames[i] = BeanUtils.fieldName(parameterNames[i], beanInfo.namingStrategy);
}
}
}

if (parameterNames == null || parameterNames.length == 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -754,10 +754,11 @@ protected static String getFieldName(
String fieldName;
if (fieldInfo.fieldName == null || fieldInfo.fieldName.isEmpty()) {
if (record) {
fieldName = method.getName();
fieldName = beanInfo.namingStrategy != null
? BeanUtils.fieldName(method.getName(), beanInfo.namingStrategy)
: method.getName();
} else {
fieldName = BeanUtils.getterName(method, beanInfo.kotlin, beanInfo.namingStrategy);

Field field;
if ((provider.userDefineMask & NAME_COMPATIBLE_WITH_FILED) != 0
&& (field = BeanUtils.getField(objectClass, method)) != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,14 @@ public void setBeanName(String beanName) {
this.beanName = beanName;
}
}

@JSONType(naming = PropertyNamingStrategy.SnakeCase)
static class ClassDto {
public String currencyCode = "840";
}

@Test
public void testClass() {
assertEquals("{\"currency_code\":\"840\"}", JSON.toJSONString(new ClassDto()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.alibaba.fastjson2;

import com.alibaba.fastjson2.annotation.JSONType;
import com.alibaba.fastjson2.reader.ObjectReaderProvider;
import com.alibaba.fastjson2.writer.ObjectWriterProvider;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class RecordNamingStrategyTest {
@JSONType(naming = PropertyNamingStrategy.SnakeCase)
public record RecordDto(String currencyCode) {}

public record GlobalRecordDto(String currencyCode) {}

@JSONType(naming = PropertyNamingStrategy.SnakeCase)
public record BooleanRecordDto(boolean isActive) {}

@Test
public void testRecordAnnotationNaming() {
assertEquals("{\"currency_code\":\"840\"}", JSON.toJSONString(new RecordDto("840")));
assertEquals(new RecordDto("840"), JSON.parseObject("{\"currency_code\":\"840\"}", RecordDto.class));
}

@Test
public void testBooleanFieldNotStripped() {
assertEquals("{\"is_active\":true}", JSON.toJSONString(new BooleanRecordDto(true)));
assertEquals(new BooleanRecordDto(true), JSON.parseObject("{\"is_active\":true}", BooleanRecordDto.class));
}

@Test
public void testRecordGlobalNaming() {

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.

[Suggestion] testRecordGlobalNaming only tests serialization — deserialization with global naming strategy is untested

The reader-side fix in ObjectReaderCreator.java:1282-1286 applies naming strategy to record constructor parameter names when beanInfo.namingStrategy is non-null. For global strategies, this value comes from ObjectReaderProvider via the BeanInfo constructor. This entire code path has zero test coverage.

A regression in reader-side global naming support for records would go undetected.

Suggested change
public void testRecordGlobalNaming() {
@Test
public void testRecordGlobalNaming() {
ObjectWriterProvider writerProvider = JSONFactory.getDefaultObjectWriterProvider();
ObjectReaderProvider readerProvider = JSONFactory.getDefaultObjectReaderProvider();
PropertyNamingStrategy prevWriter = writerProvider.getNamingStrategy();
PropertyNamingStrategy prevReader = readerProvider.getNamingStrategy();
try {
writerProvider.setNamingStrategy(PropertyNamingStrategy.SnakeCase);
readerProvider.setNamingStrategy(PropertyNamingStrategy.SnakeCase);
assertEquals("{\"currency_code\":\"840\"}", JSON.toJSONString(new GlobalRecordDto("840")));
assertEquals(new GlobalRecordDto("840"), JSON.parseObject("{\"currency_code\":\"840\"}", GlobalRecordDto.class));
} finally {
writerProvider.setNamingStrategy(prevWriter);
readerProvider.setNamingStrategy(prevReader);
}
}

— qwen3.7-max via Qwen Code /review

ObjectWriterProvider writerProvider = JSONFactory.getDefaultObjectWriterProvider();
ObjectReaderProvider readerProvider = JSONFactory.getDefaultObjectReaderProvider();
PropertyNamingStrategy prevWriter = writerProvider.getNamingStrategy();
PropertyNamingStrategy prevReader = readerProvider.getNamingStrategy();
try {
writerProvider.setNamingStrategy(PropertyNamingStrategy.SnakeCase);
readerProvider.setNamingStrategy(PropertyNamingStrategy.SnakeCase);
assertEquals("{\"currency_code\":\"840\"}", JSON.toJSONString(new GlobalRecordDto("840")));
assertEquals(new GlobalRecordDto("840"), JSON.parseObject("{\"currency_code\":\"840\"}", GlobalRecordDto.class));
} finally {
writerProvider.setNamingStrategy(prevWriter);
readerProvider.setNamingStrategy(prevReader);
}
}
}
Loading