JAXB未转换内部Wrapper DTO求助:需展示POJO字段而非对象引用
解决JSON序列化时自定义对象显示为类名@哈希码的问题
看起来你遇到了JSON序列化时自定义对象没有正确输出字段的问题——那些com.sample.commercewebservices.dto.ComplexTypeWsDTO@xxx的内容其实是对象默认toString()方法的输出,而不是你想要的DTO字段。下面是具体的解决思路和方案:
1. 核心问题:序列化框架未正确识别DTO字段
不管你用的是Jackson(Spring Boot默认)还是Gson这类序列化工具,默认情况下如果没有正确配置,框架会调用对象的toString()方法输出,就会出现这种类名+哈希码的结果。咱们需要让框架知道要序列化对象的实际字段。
针对Jackson(Spring Boot常用场景)
- 给DTO添加公共Getter方法:Jackson默认通过Getter方法识别字段,给
ComplexTypeWsDTO的每个字段补上Getter(Setter可选,反序列化时需要):
class ComplexTypeWsDTO { String complexField1; String complexField2; String complexField3; public String getComplexField1() { return complexField1; } public void setComplexField1(String complexField1) { this.complexField1 = complexField1; } // 同理添加complexField2、complexField3的Getter/Setter }
- 用Lombok简化代码:如果项目引入了Lombok,直接给
ComplexTypeWsDTO加@Data注解,自动生成Getter、Setter、toString等方法,Jackson能直接识别这些字段:
import lombok.Data; @Data class ComplexTypeWsDTO { String complexField1; String complexField2; String complexField3; }
- 配置Jackson直接序列化字段(无需Getter):如果不想写Getter,可以通过
ObjectMapper配置让框架直接访问私有字段:
@Configuration public class JacksonConfig { @Bean public ObjectMapper objectMapper() { ObjectMapper objectMapper = new ObjectMapper(); // 允许序列化所有字段,不管是否有Getter objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY); return objectMapper; } }
针对Gson
Gson默认会序列化对象的所有字段(包括私有字段),只要你没自定义覆盖默认的toString(),直接序列化就能得到正确结果:
Gson gson = new Gson(); String jsonResponse = gson.toJson(yourResponseWsDTOInstance);
如果需要自定义序列化逻辑,可以创建TypeAdapter来指定ComplexTypeWsDTO的输出格式:
class ComplexTypeWsDTOAdapter extends TypeAdapter<ComplexTypeWsDTO> { @Override public void write(JsonWriter out, ComplexTypeWsDTO value) throws IOException { out.beginObject(); out.name("complexField1").value(value.complexField1); out.name("complexField2").value(value.complexField2); out.name("complexField3").value(value.complexField3); out.endObject(); } @Override public ComplexTypeWsDTO read(JsonReader in) throws IOException { // 按需实现反序列化逻辑 ComplexTypeWsDTO dto = new ComplexTypeWsDTO(); in.beginObject(); while (in.hasNext()) { switch (in.nextName()) { case "complexField1": dto.complexField1 = in.nextString(); break; case "complexField2": dto.complexField2 = in.nextString(); break; case "complexField3": dto.complexField3 = in.nextString(); break; } } in.endObject(); return dto; } } // 使用时注册适配器 Gson gson = new GsonBuilder() .registerTypeAdapter(ComplexTypeWsDTO.class, new ComplexTypeWsDTOAdapter()) .create();
2. 自定义Map的序列化格式(匹配预期响应)
你的预期响应里,Map的value嵌套了complexType数组,而不是直接输出列表。如果要实现这个结构,需要自定义Map的序列化逻辑:
用Jackson实现自定义Map序列化
创建一个序列化器处理Map<Date, List<ComplexTypeWsDTO>>:
public class CustomMapSerializer extends JsonSerializer<Map<Date, List<ComplexTypeWsDTO>>> { @Override public void serialize(Map<Date, List<ComplexTypeWsDTO>> map, JsonGenerator gen, SerializerProvider serializers) throws IOException { gen.writeStartArray(); for (Map.Entry<Date, List<ComplexTypeWsDTO>> entry : map.entrySet()) { gen.writeStartObject(); // 自定义日期格式,和预期一致 gen.writeStringField("key", new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(entry.getKey())); gen.writeObjectFieldStart("value"); gen.writeArrayFieldStart("complexType"); // 逐个序列化ComplexTypeWsDTO对象 for (ComplexTypeWsDTO dto : entry.getValue()) { gen.writeObject(dto); } gen.writeEndArray(); gen.writeEndObject(); gen.writeEndObject(); } gen.writeEndArray(); } }
然后在ResponseWsDTO的mapFieldName字段上添加注解:
class ResponseWsDTO { @JsonSerialize(using = CustomMapSerializer.class) Map<Date, List<ComplexTypeWsDTO>> mapFieldName; String field1; String field2; // Getter/Setter }
3. 额外注意事项
- 避免自定义toString()干扰:如果
ComplexTypeWsDTO重写了toString()方法,且不是返回JSON格式内容,某些序列化配置下会优先使用这个方法,所以要么删除自定义toString(),要么让序列化框架忽略它。 - 统一日期格式:确保序列化后的日期字符串和预期一致,比如Jackson可以通过
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX"))配置。
按照上面的步骤处理后,序列化出来的JSON就会像你预期的那样,正确展示ComplexTypeWsDTO的字段内容了。
内容的提问来源于stack exchange,提问作者Pushpak U
相关产品推荐
相关产品推荐

