当前位置: 首页 > 知识库问答 >
问题:

使用Jackson Mixins与MappingJacksonHttpMessageConverter和Spring MVC

易宣
2023-03-14

我将马上讨论我真正的问题/问题,是否有任何方法访问HttpMessageConverter内部控制器处理程序方法上的注释?我很确定答案是否定的(在浏览了Spring的源代码之后)。

在使用MappingJacksonHttpMessageConverter时,是否有其他方法使用Jackson Mixins配对?我已经基于MappingJacksonHttpMessageConverter实现了自己的HttpMessageConverter,以“升级”它来使用Jackson2.0。

Controller.class

@Controller
public class Controller {

    @JsonFilter({ @JsonMixin(target=MyTargetObject.class, mixin=MyTargetMixin.class) })
    @RequestMapping(value="/my-rest/{id}/my-obj", method=RequestMethod.GET, produces="application/json")
    public @ResponseBody List<MyTargetObject> getListOfFoo(@PathVariable("id") Integer id) {
        return MyServiceImpl.getInstance().getBarObj(id).getFoos();
    }
}

@jsonfilter是一个我希望传递给映射器的自定义注释,然后可以直接自动地将其提供给ObjectMapper。

MappingJacksonHttpMessageConverter.class

public class MappingJacksonHttpMessageConverter extends AbstractHttpMessageConverter<Object> {

    ...

    @Override
    protected void writeInternal(Object object, HttpOutputMessage outputMessage) {

            //Obviously, no access to the HandlerMethod here.

    }

    ...
}

我到处寻找这个答案。到目前为止,我只看到人们在控制器的处理方法中将他们的对象序列化为JSON(在每个方法中重复违反DRY原则)。或者直接注释它们的数据对象(没有关于如何公开对象的解耦或多重配置)。

可能是在HttpMessageConverter中无法完成。还有其他选择吗?拦截器提供对HandlerMethod的访问,但不提供对处理程序方法的返回对象的访问。

共有1个答案

彭华皓
2023-03-14

这不是理想的解决方案。看我的第二个答案。

我使用ModelandViewResolver解决了这个问题。您可以直接在AnnotationMethodHandlerAdapter中注册这些代码,因为您知道它们总是会在默认处理发生之前首先启动。因此,Spring的文档-

/**
 * Set a custom ModelAndViewResolvers to use for special method return types.
 * <p>Such a custom ModelAndViewResolver will kick in first, having a chance to resolve
 * a return value before the standard ModelAndView handling kicks in.
 */
public void setCustomModelAndViewResolver(ModelAndViewResolver customModelAndViewResolver) {
    this.customModelAndViewResolvers = new ModelAndViewResolver[] {customModelAndViewResolver};
}

查看ModelandViewResolver接口,我知道它包含了将某些功能扩展到处理程序方法工作方式所需的所有参数。

public interface ModelAndViewResolver {

    ModelAndView UNRESOLVED = new ModelAndView();

    ModelAndView resolveModelAndView(Method handlerMethod,
            Class handlerType,
            Object returnValue,
            ExtendedModelMap implicitModel,
            NativeWebRequest webRequest);
}

看看ResolveModelandView中所有这些美味的参数!我几乎可以访问Spring所知道的关于该请求的所有信息。以下是我如何实现该接口,使其行为与映射JacksonHttpMessageConverter非常相似,除了单向方式(向外):

public class JsonModelAndViewResolver implements ModelAndViewResolver {

    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

    public static final MediaType DEFAULT_MEDIA_TYPE = new MediaType("application", "json", DEFAULT_CHARSET);

    private boolean prefixJson = false;

    public void setPrefixJson(boolean prefixJson) {
        this.prefixJson = prefixJson;
    }

    /**
     * Converts Json.mixins() to a Map<Class, Class>
     *
     * @param jsonFilter Json annotation
     * @return Map of Target -> Mixin classes
     */
    protected Map<Class<?>, Class<?>> getMixins(Json jsonFilter) {

        Map<Class<?>, Class<?>> mixins = new HashMap<Class<?>, Class<?>>();

        if(jsonFilter != null) {
            for(JsonMixin jsonMixin : jsonFilter.mixins()) {
                mixins.put(jsonMixin.target(), jsonMixin.mixin());
            }
        }

        return mixins;
    }

    @Override
    public ModelAndView resolveModelAndView(Method handlerMethod, Class handlerType, Object returnValue, ExtendedModelMap implicitModel, NativeWebRequest webRequest) {

        if(handlerMethod.getAnnotation(Json.class) != null) {

            try {

                HttpServletResponse httpResponse = webRequest.getNativeResponse(HttpServletResponse.class);

                httpResponse.setContentType(DEFAULT_MEDIA_TYPE.toString());

                OutputStream out = httpResponse.getOutputStream();

                ObjectMapper objectMapper = new ObjectMapper();

                objectMapper.setMixInAnnotations(getMixins(handlerMethod.getAnnotation(Json.class)));

                JsonGenerator jsonGenerator =
                        objectMapper.getJsonFactory().createJsonGenerator(out, JsonEncoding.UTF8);

                if (this.prefixJson) {
                    jsonGenerator.writeRaw("{} && ");
                }

                objectMapper.writeValue(jsonGenerator, returnValue);

                out.flush();
                out.close();

                return null;

            } catch (JsonProcessingException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return UNRESOLVED;
    }

}

上面使用的唯一自定义类是我的注释类@json,它包括一个名为mixins的参数。下面是我如何在控制器端实现这一点。

@Controller
public class Controller {

    @Json({ @JsonMixin(target=MyTargetObject.class, mixin=MyTargetMixin.class) })
    @RequestMapping(value="/my-rest/{id}/my-obj", method=RequestMethod.GET)
    public @ResponseBody List<MyTargetObject> getListOfFoo(@PathVariable("id") Integer id) {
        return MyServiceImpl.getInstance().getBarObj(id).getFoos();
    }
}

这是相当棒的简单。ModelAndViewResolver将自动将返回对象转换为JSON,并应用带注释的混合格式。

一个“缺点”(如果你这么说的话)是必须回到Spring2.5的配置方式,因为新的3.0标记不允许直接配置ModelAndViewResolver。也许他们只是忽略了这一点?

我的旧配置(使用Spring3.1样式)

<mvc:annotation-driven />

我的新配置(使用Spring2.5样式)

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> 
    <property name="customModelAndViewResolvers">
        <list>
            <bean class="my.package.mvc.JsonModelAndViewResolver" />
        </list>
    </property>
</bean>

^^3.0+无法连接自定义ModelandViewResolver。因此,切换回旧的样式。

以下是自定义注释:

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Json {

    /**
     * A list of Jackson Mixins.
     * <p>
     * {@link http://wiki.fasterxml.com/JacksonMixInAnnotations}
     */
    JsonMixin[] mixins() default {};

}
public @interface JsonMixin {
    public Class<? extends Serializable> target();
    public Class<?> mixin();
}
 类似资料:
  • 问题内容: 不合理,无法通过注释而不是纯XML Bean来配置Spring Bean,现在我正面临后果。 我使用以下方式配置REST通道 现在,我只需要简单地将设置为仅将此具有非null值的字段输出到JSON。我尝试了以下方法: Bean被创建,但是转换器的另一个实例已创建并在通道中使用。所以我已经尝试过这种方法并在Stackoverflow问题中进行了描述,但是json序列化仍然使用其自己的配置

  • 最后,我尝试通过 但我以结束。所以现在我别无选择,所以我在这里征求任何想法。如何控制和配置框架使用的映射器?

  • 问题内容: 这是一个纯Python特定的设计问题: 和 Python让我们可以用任何一种方式来做。如果要设计Python程序,将使用哪种方法,为什么? 问题答案: 首选属性。这就是他们在那里的目的。 原因是所有属性在Python中都是公共的。以一两个下划线开头的名称只是警告,给定属性是实现细节,在将来的代码版本中可能会保持不变。它不会阻止您实际获取或设置该属性。因此,标准属性访问是访问属性的常规P

  • 问题内容: 我目前正在大型数据库的某些表中启用UTF-8字符。这些表已经是MS-SQL类型NVARCHAR。另外,我也有几个使用VARCHAR的字段。 Hibernate与JDBC驱动程序的交互存在一个众所周知的问题。简而言之,Hibernate / JDBC生成的SQL会将所有字符串作为Unicode传递,而不管底层的SQL类型如何。将数据库中的非unicode(varchar)字段与Unico

  • 问题内容: 我有如下表 如何通过下面的AND组合成一个IN语句来使用Restriction.in查询? 问题答案: 我认为这是您要使用的条件组合(顺便说一句,帮助Hibernate实体bean定义而不是表结构更容易):

  • 问题内容: 我有一个包含一些Label()小部件,一些Button()小部件,一些Text()小部件和一些Entry()小部件的程序。之前进行过两次修订,我没有标签,并且Entry()小部件较少,为了方便起见,我混合了.pack()和.grid(),这很好。我必须进行一些重构,并在此过程中添加了额外的小部件- 添加的所有新内容都使用.grid()。其他小部件没有任何变化。现在,我遇到了“无法在。中