Spring HttpHeaders

时间:2018-12-31 00:46:24

标签: spring

我发现我认为可能是Spring类HttpHeadersReadOnlyHttpHeaders中的错误。我想在用Spring提高Jira缺陷之前确认这一点。这是我用来创建一个空HttpHeaders对象的代码片段:

HttpHeaders myHeaders = HttpHeaders.writableHttpHeaders(HttpHeaders.EMPTY);

然后我使用以下方法将标头添加到新对象中:

myHeaders.add(HttpHeaders.ACCEPT_ENCODING, "gzip")

HttpHeaders.EMPTY之后不再为空

HttpHeaders.EMPTY.size() == 1

HttpHeaders.EMPTY的javadoc状态:

  

/ **
       *空的{@code HttpHeaders}实例(不可变)。
       * /
      公共静态最终HttpHeaders EMPTY

这里的问题是,当在其他地方使用'HttpHeaders.EMPTY'时,它会引入意外的标头。

请考虑以下单元测试:

@Test
public void testUpdateEmptyHeaders() {
    assertEquals(0, HttpHeaders.EMPTY.size()); // **Success**
    HttpHeaders myHeaders = HttpHeaders.writableHttpHeaders(HttpHeaders.EMPTY);
    myHeaders.add(HttpHeaders.ACCEPT_ENCODING, "gzip");
    assertEquals(0, HttpHeaders.EMPTY.size()); // **Assert Fails**
}

@Test
// This test will fail if run after the test above, but will be successful if run by itself
public void testEmptyHeaders() {
    assertEquals(0, HttpHeaders.EMPTY.size()); 
}

这是单元测试的结果:

// testUpdateEmptyHeaders
08:39:28.450 [main] DEBUG org.springframework.test.context.support.AbstractDirtiesContextTestExecutionListener - After test method: context [DefaultTestContext@2e222612, testMethod = testUpdateEmptyHeaders@AuditContextTest, testException = java.lang.AssertionError: expected:<0> but was:<1>

java.lang.AssertionError: 
Expected :0
Actual   :1

// testEmptyHeaders
08:39:28.482 [main] DEBUG org.springframework.test.context.support.AbstractDirtiesContextTestExecutionListener - After test method: context [DefaultTestContext@2e222612, testMethod = testEmptyHeaders@AuditContextTest, testException = java.lang.AssertionError: expected:<0> but was:<1>

java.lang.AssertionError: 
Expected :0
Actual   :1

我认为这是一个错误,因为HttpHeaders.EMPTY应该是不变的。 我还可以通过在Spring HttpHeaders.javaReadOnlyHttpHeaders.java

中进行两项更改来解决此问题

2 个答案:

答案 0 :(得分:2)

是的,这是Spring框架HttpHeaders的错误

public static final HttpHeaders EMPTY
  
    

HttpHeaders.EMPTY这将返回空的HttpHeaders实例(不可变)。 (这是单身人士)

  

案例:1 让我们看一下HttpHeaders.Empty,它返回不可变的对象

    HttpHeaders head = HttpHeaders.EMPTY;

    System.out.println(System.identityHashCode(head));  //1338668845

    System.out.println(head.size());                    //0

    HttpHeaders myHeaders = HttpHeaders.writableHttpHeaders(HttpHeaders.EMPTY); 

    System.out.println(System.identityHashCode(myHeaders));  //159413332

    myHeaders.add(HttpHeaders.ACCEPT_ENCODING, "gzip"); 

    head = HttpHeaders.EMPTY; 
    System.out.println(System.identityHashCode(head));       //1338668845
    System.out.println(head.size());                    //1
    System.out.println(head);                            //{Accept-Encoding=[gzip]}

    HttpHeaders head1 = HttpHeaders.EMPTY;
    System.out.println(head1);                          //{Accept-Encoding=[gzip]}
    System.out.println(System.identityHashCode(head1));   //1338668845

结论:

  

1:HttpHeaders.EMPTY始终返回单例对象

     

2:问题是当内部将HttpHeaders.EMPTY传递给writableHttpHeaders方法时,返回的对象与HttpHeaders.EMPTY单例对象有关系,请看情况2

案例:2 writableHttpHeaders返回的对象(内部和间接)反映为HttpHeaders.EMPTY单例对象

    HttpHeaders head = HttpHeaders.EMPTY;           

    System.out.println(System.identityHashCode(head));  //1338668845

    System.out.println(head.size());                //0

    HttpHeaders myHeaders = HttpHeaders.writableHttpHeaders(HttpHeaders.EMPTY); 

    System.out.println(System.identityHashCode(myHeaders));  //159413332

    myHeaders.add(HttpHeaders.ACCEPT_ENCODING, "gzip"); 

    myHeaders.add("hello", "value");

    head = HttpHeaders.EMPTY; 
    System.out.println(System.identityHashCode(head));  //1338668845
    System.out.println(head.size());              //2
    System.out.println(head);                     //{Accept-Encoding=[gzip], hello=[value]}

    HttpHeaders head1 = HttpHeaders.EMPTY;
    System.out.println(head1);                    //{Accept-Encoding=[gzip], hello=[value]}
    System.out.println(System.identityHashCode(head1));   //1338668845

    myHeaders.remove("hello");

    System.out.println(System.identityHashCode(head));     //1338668845
    System.out.println(head.size());                 //1
    System.out.println(head);                       //{Accept-Encoding=[gzip]}

    System.out.println(head1);                        //{Accept-Encoding=[gzip]}
    System.out.println(System.identityHashCode(head1));    //1338668845

结论:

  

1:对add对象执行的removemyHeaders操作反映到HttpHeaders.EMPTY对象

案例3:假设如果我们使用构造函数将HttpHeaders对象的空实例传递给writableHttpHeaders,那么一切正常就不会出现问题

    HttpHeaders head = HttpHeaders.EMPTY;

    System.out.println(System.identityHashCode(head));       //1338668845

    System.out.println(head.size());                     //0

    HttpHeaders myHeaders = HttpHeaders.writableHttpHeaders(new HttpHeaders()); 

    System.out.println(System.identityHashCode(myHeaders));       //1323165413

    myHeaders.add(HttpHeaders.ACCEPT_ENCODING, "gzip"); 

    myHeaders.add("hello", "value");

    head = HttpHeaders.EMPTY; 
    System.out.println(System.identityHashCode(head));           //1338668845
    System.out.println(head.size());                    //0
    System.out.println(head);                           //{}

    HttpHeaders head1 = HttpHeaders.EMPTY;
    System.out.println(head1);                           //{}
    System.out.println(System.identityHashCode(head1));   //1338668845

案例:4 即使可以修改间接不变的HttPHeaders.EMPTY,但是如果您尝试直接修改,它仍然会引发错误

    HttpHeaders head = HttpHeaders.EMPTY;

    System.out.println(System.identityHashCode(head));

    System.out.println(head.size());

    HttpHeaders myHeaders = HttpHeaders.writableHttpHeaders(HttpHeaders.EMPTY); 

    System.out.println(System.identityHashCode(myHeaders));

    myHeaders.add(HttpHeaders.ACCEPT_ENCODING, "gzip"); 

    head = HttpHeaders.EMPTY; 
    System.out.println(System.identityHashCode(head));
    System.out.println(head.size());
    System.out.println(head);

    head.add("hello", "value");

输出:

1338668845
0
159413332
1338668845
1
{Accept-Encoding=[gzip]}
Exception in thread "main" java.lang.UnsupportedOperationException
at org.springframework.http.ReadOnlyHttpHeaders.add(ReadOnlyHttpHeaders.java:67)
at com.demo.NestedJsonParse.main(NestedJsonParse.java:40)

最终结论:是的,您可以针对spring项目spring-bug提出一个错误,不可变的对象无法更改状态

答案 1 :(得分:1)

我已经报告了此错误,并且根据https://jira.spring.io/browse/SPR-17633

在Spring 5.1.4中已修复。