我发现我认为可能是Spring类HttpHeaders
和ReadOnlyHttpHeaders
中的错误。我想在用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.java
和ReadOnlyHttpHeaders.java
答案 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
对象执行的remove
和myHeaders
操作反映到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中已修复。