为什么ResponseBody和Jackson ObjectMapper不返回相同的输出?

如何解决为什么ResponseBody和Jackson ObjectMapper不返回相同的输出?

我正在使用Spring Boot应用程序。

我的控制器中有一个返回一些资源的方法:

    @ResponseBody
    @Transactional(rollbackFor = Exception.class)
    @GetMapping(value="data/{itemId}/items",produces="application/json")
    public Resources<DataExcerpt> listMyData(@PathVariable("debateId") UUID debateId)){

       List<DataExcerpt> dataExcerpts = dataService
                .listMyData(id)
                .stream()
                .map(d -> this.projectionFactory.createProjection(DataExcerpt.class,d))
                .collect(Collectors.toList());
        return new Resources<>(dataExcerpts);
    }

这将以以下形式返回内容:

{
  "_embedded" : {
    "items" : [ {
      "position" : {
        "name" : "Oui","id" : "325cd3b7-1666-4c44-a55f-1e7cc936a3aa","color" : "#51B63D","usedForPositionType" : "FOR_CON"
      },"id" : "5aa48cfb-5505-43b6-b0a9-5481c895e2bf","item" : [ {
        "index" : 0,"id" : "43c2dcd0-6bdb-43b0-be97-2a40b99bc753","description" : {
          "id" : "021ad7cd-4bf1-4dce-9ea7-10980440a049","title" : "Item description","modificationCount" : 0
        }
      } ],"title" : "Item title","originalMaker" : {
        "username" : "jeremieca","id" : "cfae1a04-cb00-4ad4-b4e8-6971eff64807","avatarUrl" : "user-16","_links" : {
          "self" : {
            "href" : "http://some-api-link"
          }
        }
      },"itemState" : {
        "itemState" : "LIVE",},"opinionImprovements" : [ ],"sourcesJson" : [ ],"makers" : [ {
        "username" : "jeremieca","_links" : {
          "self" : {
            "href" : "http://some-api-link"
          }
        }
      } ],"modificationsCounter" : 1,"originalBuyer" : "fd9b68f9-7c0c-4120-869c-c63d1680e7f0","updateTrace" : {
        "createdOn" : "2020-05-25T08:12:56.846+0000","createdBy" : "cfae1a04-cb00-4ad4-b4e8-6971eff64807","updatedOn" : "2020-05-25T08:12:56.845+0000","updatedBy" : "cfae1a04-cb00-4ad4-b4e8-6971eff64807"
      },"_links" : {
        "self" : {
          "href" : "some-api-link","templated" : true
        },"newEditions" : {
          "href" : "some-api-link","makers" : {
          "href" : "http://some-api-link"
        },"originalMaker" : {
          "href" : "http://some-api-link"
        }
      }
    } ]
  }
}

另一方面,我也想在Redis中缓存这些答案,以避免每次都运行整个过程。为此,我正在使用Jackson的ObjectMapper将我的资源转换为字符串

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.writeValueAsString(controller.listMyData(id)); // the same function as above

writeValueAsString 输出的结构与第一个不同:

"{content: [...],_links: []}"

因此,当我从具有缓存内容的API返回时,其结构与控制器在没有缓存的情况下向我发送的结构不同。

那是为什么? Jackson是否无法正确将Resources Hateoas结构写为字符串? 我想念什么吗?

编辑

这是Resources.class:

package org.springframework.hateoas;

import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import org.springframework.util.Assert;

@XmlRootElement(name = "entities")
public class Resources<T> extends ResourceSupport implements Iterable<T> {
    private final Collection<T> content;

    protected Resources() {
        this(new ArrayList(),(Link[])());
    }

    public Resources(Iterable<T> content,Link... links) {
        this(content,(Iterable) Arrays.asList(links));
    }

    public Resources(Iterable<T> content,Iterable<Link> links) {
        Assert.notNull(content,"Content must not be null!");
        this.content = new ArrayList();
        Iterator var3 = content.iterator();

        while (var3.hasNext()) {
            T element = var3.next();
            this.content.add(element);
        }

        this.add(links);
    }

    public static <T extends Resource<S>,S> Resources<T> wrap(Iterable<S> content) {
        Assert.notNull(content,"Content must not be null!");
        ArrayList<T> resources = new ArrayList();
        Iterator var2 = content.iterator();

        while (var2.hasNext()) {
            S element = var2.next();
            resources.add(new Resource(element,new Link[0]));
        }

        return new Resources(resources,new Link[0]);
    }

    @XmlAnyElement
    @XmlElementWrapper
    @JsonProperty("content")
    public Collection<T> getContent() {
        return Collections.unmodifiableCollection(this.content);
    }

    public Iterator<T> iterator() {
        return this.content.iterator();
    }

    public String toString() {
        return String.format("Resources { content: %s,%s }",this.getContent(),super.toString());
    }

    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        } else if (obj != null && obj.getClass().equals(this.getClass())) {
            Resources<?> that = (Resources) obj;
            boolean contentEqual = this.content == null ? that.content == null : this.content.equals(that.content);
            return contentEqual ? super.equals(obj) : false;
        } else {
            return false;
        }
    }

    public int hashCode() {
        int result = super.hashCode();
        result += this.content == null ? 0 : 17 * this.content.hashCode();
        return result;
    }
}

谢谢。

解决方法

原因是,当Spring使用HATEOAS配置MVC或Spring Boot应用程序时,它将配置自定义的Jackson模块,以处理Resources类以及对象的其余部分的序列化和反序列化过程API公开的模型。

如果要获得类似的结果,可以执行以下操作:

import org.springframework.hateoas.mediatype.hal.Jackson2HalModule;

// ...

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new Jackson2HalModule());
objectMapper.writeValueAsString(controller.listMyData(id));

,

我的建议是提供扩展hateoas'ResourceSupport的POJO,(反序列化)将通过POJO进行。

ResourcesJson(根元素)

public class ResourcesJson extends ResourceSupport {
    @JsonProperty("_embedded")
    private ResourcesEmbeddedListJson  embedded;

    //getters and setters
}

嵌入“包装器”

public class ResourcesEmbeddedListJson extends ResourceSupport {
    private Collection<T> content;

    //getters and setters
}

或者,如果您不想让它变得丑陋,可以使用此org.springframework.hateoas.client.Traverson组件。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-