我正在将当前的 Spring Boot 2.6.7 升级到 Spring Boot 3.1.4。我已经更新了所有依赖项并重新导入了所有必需的包。这是一个多租户应用程序。
我正在使用 Postgres 数据库。为了获取 JSON 格式的查询结果,我正在按以下格式编写本机查询
select Row_to_json(list) as response, row_number() over() as id from (
select * from sch.employees )list
下面是将实体管理器中的结果提取为所需格式的代码。
public <T> Optional<List<T>> getResultList(String[] parametersName, Object[] parametersValues, Class<T> klazz, String queryString) { try { Query nativeQuery = em.createNativeQuery(queryString, NativeQueryResponse.class); for (int i = 0; i < parametersName.length; i++) { nativeQuery.setParameter(parametersName[i], parametersValues[i]); } List<NativeQueryResponse<T>> details = nativeQuery.getResultList(); Type typeOfT = TypeToken.getParameterized(List.class, klazz).getType(); List<T> response; if (!details.isEmpty() && details.get(0).getResponse() instanceof List) { response = (List<T>) details.get(0).getResponse(); } else { response = details.stream().map(NativeQueryResponse::getResponse) .collect(Collectors.toCollection(ArrayList::new)); } em.clear(); return Optional.of(gson.fromJson(gson.toJson(response), typeOfT)); } catch (Exception e) { log.error("error while executing query {} with parameters as {} and parameters values as {} ", queryString, parametersName, parametersValues); CommonUtils.printStackTrack(e); return Optional.empty(); } }
它也返回数据并最终将其映射到所需的对象。下边是 它映射到的类。
public class NativeQueryResponse<T> {
@Id
@Column(name = "id", updatable = false, nullable = false)
private Long id;
@Type(JsonType.class)
@Column(columnDefinition = "jsonb")
T response;
}
它也在创建员工对象列表。在我的班级下面要反序列化。
@Setter
@Getter
public class Employee {
@SerializedName(value = "id")
private Long id;
@SerializedName(value = "first_name")
private String firstName;
@SerializedName(value = "middle_name")
private String middleName;
@SerializedName(value = "dob")
private String dob;
}
即使在控制器层,我也可以看到员工列表,其每个属性都填充了数据,但是在返回响应时,它不会在定义的java属性中发送响应,而是以我定义的serializedName发送响应
{
"id": 1,
"first_name": "User 1",
"middle_name": "M name",
"dob": ""
}
预计是
{
"id": 1,
"firstName": "User 1",
"middleName": "M name",
"dob": ""
}
我什至浏览了github链接,上面说的是定义
spring.http.converters.preferred-json-mapper:gson
但即使在那之后,它仍然在我为 SerializedName 定义的属性中返回 API 响应,或者就像我们从数据库查询返回的那样。
以下是应用程序中当前的春季安全更新
@Bean SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.csrf(AbstractHttpConfigurer::disable).authorizeHttpRequests( request -> request.requestMatchers(HttpMethod.OPTIONS).permitAll().requestMatchers("/**").permitAll()) .sessionManagement(manager -> manager.sessionCreationPolicy(STATELESS)) .addFilterBefore(new AuthenticationFilter(environment), UsernamePasswordAuthenticationFilter.class); return http.build(); }
更多配置细节以供更多分析。
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<project.reports.dir>${basedir}/target/reports</project.reports.dir>
<java.version>20</java.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<json-path.version>2.4.0</json-path.version>
<org.projectlombok.version>1.18.24</org.projectlombok.version>
<org.mapstruct.version>1.5.5.Final</org.mapstruct.version>
<log4j2.version>2.17.0</log4j2.version>
我不确定具体问题出在哪里。每个API都是这样的,但是如果我使用JPA存储库来获取API中的数据,它们会正确返回结果。只有当我使用GSON反序列化时才会出现这个问题。
如果上述实施似乎不正确或未作为最佳实践的一部分正确实施,请提出建议。
您的序列化器正在完全按照您的要求进行操作。您甚至不需要考虑导致创建员工列表的所有逻辑;您需要知道的是,您有一份员工列表,但这些员工没有按照您认为应该的方式进行序列化。
考虑这个测试
@Test
public void testIt() {
List<Employee> employees = new ArrayList<>();
employees.add(Employee.builder().firstName("bob").middleName("middle bob").build());
employees.add(Employee.builder().firstName("bill").middleName("middle bill").build());
Assertions.assertEquals("[{\"firstName\":\"bob\",\"middleName\":\"middle bob\"},{\"firstName\":\"bill\",\"middleName\":\"middle bill\"}]", new Gson().toJson(employees));
}
如果你现在运行它,它将失败并显示
org.opentest4j.AssertionFailedError:
Expected :[{"firstName":"bob","middleName":"middle bob"},{"firstName":"bill","middleName":"middle bill"}]
Actual :[{"first_name":"bob","middle_name":"middle bob"},{"first_name":"bill","middle_name":"middle bill"}]
现在,删除 Employee 类上的那些注释,这些注释专门告诉序列化器将
firstName
序列化为 first_name
和 middleName
为 middle_name
,然后再次运行测试。这次你的测试将通过。
您的序列化正在完全按照您的指示进行。如果在您之前的实现中,即使您将
SerializedName
设置为 first_name
,它仍将firstName 序列化为firstName,那么这是因为您在之前的版本中出现了错误。