JSON parse error: Cannot deserialize value of type `long` from String "经济作物": not a valid `long` value; nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `long` from String "经济作物": not a valid `long` value at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 1, column: 198] (through reference chain: com.ruoyi.farm.domain.FarmGoods["goodsType"])
时间: 2025-05-28 16:52:05 浏览: 4
### 问题分析
在Spring框架中,当尝试将JSON数据反序列化为Java对象时,如果字段的数据类型不匹配,则会抛出`InvalidFormatException`或其他类似的Jackson异常。具体来说,在当前场景下,“goodsType”字段被定义为`Long`类型,而实际接收到的JSON值是一个字符串 `'经济作物'`,这显然无法直接转换为`Long`。
以下是针对该问题的具体解释以及解决方案:
---
### 错误原因
Jackson默认情况下不会自动将字符串(如“经济作物”)转换为目标类型的数值(如`Long`)。因此,当尝试解析如下JSON结构时会发生错误:
```json
{
"goodsType": "经济作物"
}
```
由于目标类中的`goodsType`字段声明为`Long`类型,而传入的值是字符串形式,Jackson无法完成类型映射并抛出了`InvalidFormatException`[^1]。
---
### 解决方案
#### 方法一:修改字段类型以适配输入数据
最简单的解决方法是调整目标类中`goodsType`字段的类型,使其能够接受字符串值。例如,将其改为`String`类型:
```java
public class FarmGoods {
private String goodsType; // 修改为String类型
// Getter and Setter methods...
public String getGoodsType() {
return goodsType;
}
public void setGoodsType(String goodsType) {
this.goodsType = goodsType;
}
}
```
通过这种方式可以避免因类型不匹配引发的异常。不过需要注意的是,后续逻辑可能需要额外处理这些字符串值以便于业务需求[^2]。
#### 方法二:自定义反序列化器
如果确实希望保持`goodsType`作为`Long`类型,那么可以通过实现自定义的Jackson反序列化器来解决问题。下面展示如何创建一个定制化的反序列化器用于处理这种情况:
```java
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import java.io.IOException;
public class CustomLongDeserializer extends JsonDeserializer<Long> {
@Override
public Long deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
String value = jp.getText();
try {
if ("经济作物".equals(value)) {
return 1L; // 假设"经济作物"对应数据库ID为1
} else if ("粮食作物".equals(value)) {
return 2L; // 类似地设置其他映射关系
}
throw new RuntimeException("未知的商品类型:" + value);
} catch (NumberFormatException e) {
throw new RuntimeException("商品类型转换失败:" + value, e);
}
}
}
```
接着注册这个自定义反序列化器至目标属性上:
```java
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
public class FarmGoods {
@JsonDeserialize(using = CustomLongDeserializer.class)
private Long goodsType;
// Getter and Setter methods...
public Long getGoodsType() {
return goodsType;
}
public void setGoodsType(Long goodsType) {
this.goodsType = goodsType;
}
}
```
这种方法允许保留原始模型设计的同时灵活应对各种复杂情况下的数据绑定[^3]。
#### 方法三:预处理请求体
另一种可行的办法是在接收前端发送来的HTTP请求之前先做一层转化工作——即把那些不符合预期格式的内容提前修正好再交给控制器层去进一步操作。比如利用拦截器或者过滤器机制对特定路径下的所有POST/PUT请求执行统一改造动作。
假设我们有一个全局配置文件存储着所有的枚举项及其对应的编码表,则可以在应用启动阶段加载它们,并基于此构建一套快速查找算法供后面调用:
```java
@Component
public class RequestBodyPreprocessor implements Filter {
Map<String, Long> enumMappingTable = new HashMap<>();
@PostConstruct
public void initEnumMappings(){
enumMappingTable.put("经济作物", 1L);
enumMappingTable.put("粮食作物", 2L);
// Add more mappings as needed.
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest)request;
HttpServletResponse httpResponse = (HttpServletResponse)response;
if ("/api/farm-goods".equalsIgnoreCase(httpRequest.getRequestURI())) {
BufferedReader reader = httpRequest.getReader();
StringBuilder requestBodyBuilder = new StringBuilder();
int c;
while ((c = reader.read()) != -1){
requestBodyBuilder.append((char)c);
}
JSONObject jsonObject = new JSONObject(requestBodyBuilder.toString());
String rawValue = jsonObject.optString("goodsType");
if (!enumMappingTable.containsKey(rawValue)){
httpResponse.sendError(HttpServletResponse.SC_BAD_REQUEST,"无效的商品类型");
return ;
}
jsonObject.put("goodsType", enumMappingTable.get(rawValue));
MockHttpServletRequestWrapper wrapper =
new MockHttpServletRequestWrapper(httpRequest){
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayInputStream =
new ByteArrayInputStream(jsonObject.toString().getBytes(StandardCharsets.UTF_8));
return new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setReadListener(ReadListener readListener) {}
@Override
public int read() throws IOException {
return byteArrayInputStream.read();
}
};
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
};
chain.doFilter(wrapper,response);
}else{
chain.doFilter(request,response);
}
}
}
```
这样做的好处是可以集中管理不同API间共通的部分逻辑而不必重复编写相似代码片段;缺点则是增加了系统的整体复杂度并且可能会带来一定的性能开销[^4]。
---
### 总结
对于本案例而言,推荐优先考虑 **方法一** 或者 **方法二** ,因为这两种方式相对简单明了而且易于维护。只有当项目规模较大且存在大量类似问题待解决时才建议采用 **方法三** 进行批量优化。
阅读全文
相关推荐


















