杰克逊序列化没有正确处理单引号

Posted

技术标签:

【中文标题】杰克逊序列化没有正确处理单引号【英文标题】:Jackson serialization not handling single quote properly 【发布时间】:2013-02-09 02:53:14 【问题描述】:

由于与 Spring 框架的集成,我刚刚开始使用 Jackson,并且遇到了值中单引号的问题。尝试在页面上使用 jQuery 解析 JSON 时,我收到一个 javascript 错误 "SyntaxError: missing ) after argument list"。我习惯使用 Gson 来序列化我的对象并且不会遇到这个问题,因为 Gson 会用 Unicode \u0027 替换单引号。

例如;Java

public final class Person 
  private String firstName;
  private String lastName;

  public Person() 

  public void setFirstName(String firstName) 
    this.firstName = firstName;
  

  public String getFirstName() 
    return firstName;
  

  public void setLastName(String lastName) 
    this.lastName = lastName;
  

  public String getLastName() 
    return lastName;
  

JSON 在杰克逊 ["person":"firstName":"James","lastName":"O'tool"] 在格森 ["person":"firstName":"James","lastName":"O\u0027tool"]

JavaScript; // This is where the JavaScript fails with the Jackson serialized object $.parseJSON('$requestScope.person');

我一直在寻找解决方案,但找不到。 有谁知道是否可以像 Gson 一样配置 Jackson 来处理单引号?

感谢您的宝贵时间。

【问题讨论】:

不要尝试以字符串文字输出 JSON(当然是转义)并解析它们。只需输出 Object Literals! 抱歉,我忘了说明这不是 ajax 调用,JSON 对象的解析发生在 JSP 上。如果这是一个直接的 ajax 调用,就不会有问题。 不,您正在尝试使用 JavaScript(不是 JSP)解析(错误转义的)JSON 字符串 我明白这一点。 Google 的 Gson 库默认执行此操作,我只是想知道 Jackson 是否可以通过某种方式执行此操作。 Jason 的一篇关于 json 的帖子,谈到了 jackson,然后用 Gson 的一些代码解决了这个问题。我的脑袋明白这一点为时已晚...... :) 【参考方案1】:

@Bergi 想说:不要使用:

$.parseJSON('$requestScope.person')

简单地使用

$requestScope.person

直接!

【讨论】:

这很有趣:您从客户端解释了评论,而我从服务器端解释了它。我以为@Bergi 是在说将对象传递给杰克逊,这样它就不会转义字符串中的引号字符。【参考方案2】:

另一个答案显示了一种方法,它应该工作得很好。

但还有另一种方法可以做到这一点,它的工作量更少,在“Forcing escaping of html characters in JSON using Jackson”中解释了

【讨论】:

这就是我想要的。谢谢!我只是希望有一种方法可以在 Spring 中使用 Jackson2ObjectMapperFactoryBean 类注册自定义 CharacterEscapes。 可能值得向 Spring 开发团队建议?【参考方案3】:

为了解决这个问题,我最终为 Jackson 创建了一个自定义字符串序列化程序。我从 Gson 那里借了一些资源。

    public class HtmlStringSerializer extends StdSerializer<String> 
      protected HtmlStringSerializer()  super(String.class); 

      private static final String[] HTML_SAFE_REPLACEMENT_CHARS;
      static 
        HTML_SAFE_REPLACEMENT_CHARS = new String[128];
        for (int i = 0; i <= 0x1f; i++) 
          HTML_SAFE_REPLACEMENT_CHARS[i] = String.format("\\u%04x", i);
        
        HTML_SAFE_REPLACEMENT_CHARS['"'] = "\\\"";
        HTML_SAFE_REPLACEMENT_CHARS['\\'] = "\\\\";
        HTML_SAFE_REPLACEMENT_CHARS['\t'] = "\\t";
        HTML_SAFE_REPLACEMENT_CHARS['\b'] = "\\b";
        HTML_SAFE_REPLACEMENT_CHARS['\n'] = "\\n";
        HTML_SAFE_REPLACEMENT_CHARS['\r'] = "\\r";
        HTML_SAFE_REPLACEMENT_CHARS['\f'] = "\\f";
        HTML_SAFE_REPLACEMENT_CHARS['<'] = "\\u003c";
        HTML_SAFE_REPLACEMENT_CHARS['>'] = "\\u003e";
        HTML_SAFE_REPLACEMENT_CHARS['&'] = "\\u0026";
        HTML_SAFE_REPLACEMENT_CHARS['='] = "\\u003d";
        HTML_SAFE_REPLACEMENT_CHARS['\''] = "\\u0027";
      

      @Override
      public void serialize(String string, JsonGenerator gen, SerializerProvider provider) throws IOException, JsonProcessingException 
        int last = 0;
        int length = string.length();
        StringBuilder sb = new StringBuilder(length);

        for (int i = 0; i < length; i++) 
          char c = string.charAt(i);
          String replacement;
          if (c < 128) 
            replacement = HTML_SAFE_REPLACEMENT_CHARS[c];
            if (replacement == null)  continue; 
           else if (c == '\u2028') 
            replacement = "\\u2028";
           else if (c == '\u2029') 
            replacement = "\\u2029";
           else 
            continue;
          
          if (last < i) 
        sb.append(string.substring(last, i));
          
          sb.append(replacement);
          last = i + 1;
        
        if (last < length) 
          sb.append(string.substring(last));
        
        gen.writeString(sb.toString());
      
    

【讨论】:

以上是关于杰克逊序列化没有正确处理单引号的主要内容,如果未能解决你的问题,请参考以下文章

杰克逊的 JSON 注入修复

反序列化的改造/杰克逊错误

某些字段的杰克逊 JSON 自定义序列化

Spring框架中的Jackson反序列化错误处理

杰克逊反序列化阵列通量

杰克逊:反序列化为每个值都具有正确类型的 Map<String, Object>