Spring Rest POST Json请求体Content type不受支持。

70
当我尝试使用 post 方法发布新对象时,RequestBody 无法识别 contentType。Spring 已经被配置了,并且 POST 方法可以与其他对象一起工作,但是不能与这个特定的对象一起工作。
org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/json;charset=UTF-8' not supported

如果我尝试改变请求体对象并发送同样的请求,它能够正常工作。


如果您没有设置Content type=application/json,则会出现略有不同的错误。 - Vishal Maral
Jackson反序列化器可能会出现问题。请参考链接 - Pratik Chaudhari
由于具有多个字段getter可能会出现问题。请参考链接 - Pratik Chaudhari
17个回答

86

我找到了解决方法。问题在于我有两个setter的名称相同但类型不同。

我的类中有一个int类型的id属性,当我将对象传递给Hibernate时,我用Integer类型替换了它。

但显然,我忘记删除其中一个setter,导致代码出现了以下问题:

/**
 * @param id
 *            the id to set
 */
public void setId(int id) {
    this.id = id;
}

/**
 * @param id
 *            the id to set
 */
public void setId(Integer id) {
    this.id = id;
}

当我移除了这个setter方法后,REST请求非常正常。

不会抛出解组错误或反射类错误。在这里,异常HttpMediaTypeNotSupportedException似乎非常奇怪。

我希望这篇stackoverflow可以帮助其他人。

SIDE NOTE

您可以检查您的Spring服务器控制台以获取以下错误消息:

无法评估Jackson对类型[simple type,class your.package.ClassName]的反序列化: com.fasterxml.jackson.databind.JsonMappingException:属性“propertyname”的setter定义冲突

然后您就可以确定您正在处理上述问题。


5
我在同一个问题上花费了约5个小时的时间。我在一个名为“getSerial(...)”的实体中有两个设置器。一个接受“String”,另一个接受“BigInteger”。 - Thomas Uhrig
一样的情况... 枚举类型有一个,字符串类型也有一个... 谢谢您。 - Kevin Rave
谢谢你。我无法追踪导致错误的原因,而且那个错误消息比我检查的要早得多。搜索反序列化错误直接指向了问题所在。 - gdawgrancid
显然,异常信息不准确。可以通过将有效载荷作为字符串接受,然后尝试将其序列化为相应的映射对象来找出实际错误。 - Amrit Kr Lama
https://github.com/fasterxml/jackson-databind/issues/1044 - schemacs

8

如果您为参数声明了getter和setter,而这些属性在POST中没有发送(即使它们没有在构造函数中声明),请注意:

@RestController
public class TestController {

    @RequestMapping(value = "/test", method = RequestMethod.POST)
    public String test(@RequestBody BeanTest beanTest) {
        return "Hello " + beanTest.getName();
    }


    public static class BeanTest {

        private Long id;
        private String name;

        public BeanTest() {
        }

        public BeanTest(Long id) {
            this.id = id;
        }

        public Long getId() {
            return id;
        }

        public void setId(Long id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}

使用以下结构的POST请求: {"id":"1"} 是不起作用的,您必须删除名称get和set。


真的吗?这意味着所有字段都必须设置吗? - Chris Neve

6
如果您使用Lombok,当您未正确命名@JsonDeserialize时,就可能会出现该错误,例如:
@Value
@Builder(toBuilder = true)
@JsonDeserialize(builder = SomeClass.SomeOtherClassBuilder.class)
public class SomeClass {
    ...
    public static class SomeOtherClassBuilder {
        ...
    }
}

应该是:

@Value
@Builder(toBuilder = true)
@JsonDeserialize(builder = SomeClass.SomeClassBuilder.class)
public class SomeClass {
    ...
    public static class SomeClassBuilder {
        ...
    }
}

当你重构类名时忘记了Builder,这样做非常容易......然后你就会花费许多时间去寻找错误的原因,并且只有极其不实用的异常信息来帮助你。


1
在我的情况下,我遇到了这个问题,因为我在一个字段上使用了@JsonSerialize,但是缺少了@JsonDeserialize注释。 - erran

4

真的!在花费了4个小时并疯狂地进行调试之后,我在com.fasterxml.jackson.databind.deser.DeserializerCache中找到了这个非常奇怪的代码。

if (deser == null) {
    try {
        deser = _createAndCacheValueDeserializer(ctxt, factory, type);
    } catch (Exception e) {
        return false;
    }
}

是的,问题出在双重赋值。

2

我遇到了同样的问题,通过自己反序列化已发布的值来解决:

@RequestMapping(value = "/arduinos/commands/{idArduino}", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public String sendCommandesJson(@PathVariable("idArduino") String idArduino, HttpServletRequest request) throws IOException {
    // getting the posted value
    String body = CharStreams.toString(request.getReader());
    List<ArduinoCommand> commandes = new ObjectMapper().readValue(body, new TypeReference<List<ArduinoCommand>>() {
    });

使用以下Gradle依赖项:
  compile('org.springframework.boot:spring-boot-starter-web')
  compile('com.google.guava:guava:16.0.1')

2

当我有两个setter方法,一个是枚举类型,一个是字符串类型时,我遇到了相同的问题。我必须使用@JsonSetter注释来告诉Jackson在序列化期间使用哪个setter方法。这解决了我的问题。


2

在我的情况下,bean 中有两个构造函数,导致了相同的错误。我刚刚删除了其中一个构造函数,现在问题已经解决了!


1

我遇到了一个类似的问题,其中一个bean有一些重载构造函数。这个bean还有可选属性。

为了解决这个问题,我只需删除重载构造函数即可。

例如:

public class Bean{

Optional<String> string;
Optional<AnotherClass> object;

public Bean(Optional<String> str, Optional<AnotherClass> obj){
string = str;
object = obj;
}

///The problem was below constructor

public Bean(Optional<String> str){
string = str;
object = Optional.empty();
}



}

}

1
当我使用Java 9+模块时,遇到了这个问题。我必须open该模块,以便com.fasterxml.jackson.databind可以通过反射访问对象。或者,如果你只有一个包含模型的包,你也可以只打开该包。

1
如果同一属性有两个getter,则反序列化器会失败。请参考链接

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接