diff --git a/CHANGELOG.md b/CHANGELOG.md
index ce920e7b2..4182165dc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@
* 【core 】 增加ReflectUtil.getFieldValue支持Alias注解
* 【core 】 Bean字段支持Alias注解(包括转map,转bean等)
* 【core 】 增加ValueListHandler,优化结果集获取方式
+* 【http 】 支持patch方法(issue#666@Github)
### Bug修复
diff --git a/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java b/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java
index 3da787edb..f4d559fc4 100644
--- a/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java
@@ -1849,7 +1849,9 @@ public class DateUtil {
* @param checkDate 检查时间,可以是当前时间,既
* @return 是否过期
* @since 5.1.1
+ * @deprecated 使用isIn方法
*/
+ @Deprecated
public static boolean isExpired(Date startDate, Date endDate, Date checkDate) {
return betweenMs(startDate, checkDate) > betweenMs(startDate, endDate);
}
diff --git a/hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java
index 8ea51107b..46cb279fd 100644
--- a/hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java
@@ -294,7 +294,7 @@ public class ReflectUtil {
/**
* 设置字段值
*
- * @param obj 对象
+ * @param obj 对象,static字段则此处传Class
* @param fieldName 字段名
* @param value 值,值类型必须与字段类型匹配,不会自动转换对象类型
* @throws UtilException 包装IllegalAccessException异常
@@ -303,7 +303,7 @@ public class ReflectUtil {
Assert.notNull(obj);
Assert.notBlank(fieldName);
- final Field field = getField(obj.getClass(), fieldName);
+ final Field field = getField((obj instanceof Class) ? (Class>)obj : obj.getClass(), fieldName);
Assert.notNull(field, "Field [{}] is not exist in [{}]", fieldName, obj.getClass().getName());
setFieldValue(obj, field, value);
}
@@ -317,9 +317,7 @@ public class ReflectUtil {
* @throws UtilException UtilException 包装IllegalAccessException异常
*/
public static void setFieldValue(Object obj, Field field, Object value) throws UtilException {
- Assert.notNull(field, "Field in [{}] not exist !", obj.getClass().getName());
-
- setAccessible(field);
+ Assert.notNull(field, "Field in [{}] not exist !", obj);
if (null != value) {
Class> fieldType = field.getType();
@@ -332,10 +330,11 @@ public class ReflectUtil {
}
}
+ setAccessible(field);
try {
- field.set(obj, value);
+ field.set(obj instanceof Class ? null : obj, value);
} catch (IllegalAccessException e) {
- throw new UtilException(e, "IllegalAccess for {}.{}", obj.getClass(), field.getName());
+ throw new UtilException(e, "IllegalAccess for {}.{}", obj, field.getName());
}
}
diff --git a/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java
index 8655953b7..1d1fab4a4 100644
--- a/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java
+++ b/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java
@@ -82,6 +82,14 @@ public class DateUtilTest {
Assert.assertEquals("2017-03-01 23:59:59", endOfDay.toString());
}
+ @Test
+ public void truncateTest(){
+ String dateStr2 = "2020-02-29 12:59:34";
+ Date date2 = DateUtil.parse(dateStr2);
+ final DateTime dateTime = DateUtil.truncate(date2, DateField.MINUTE);
+ Assert.assertEquals("2020-02-29 12:59:00", dateTime.toString());
+ }
+
@Test
public void beginAndWeedTest() {
String dateStr = "2017-03-01 22:33:23";
diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpConnection.java b/hutool-http/src/main/java/cn/hutool/http/HttpConnection.java
index 1a954063f..bd73c99b2 100644
--- a/hutool-http/src/main/java/cn/hutool/http/HttpConnection.java
+++ b/hutool-http/src/main/java/cn/hutool/http/HttpConnection.java
@@ -2,11 +2,10 @@ package cn.hutool.http;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
-import cn.hutool.http.ssl.AndroidSupportSSLFactory;
import cn.hutool.http.ssl.DefaultSSLInfo;
-import cn.hutool.http.ssl.SSLSocketFactoryBuilder;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
@@ -14,6 +13,8 @@ import javax.net.ssl.SSLSocketFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.Proxy;
@@ -21,17 +22,14 @@ import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
-import java.security.KeyManagementException;
-import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
/**
* http连接对象,对HttpURLConnection的包装
- *
- * @author Looly
*
+ * @author Looly
*/
public class HttpConnection {
@@ -41,9 +39,9 @@ public class HttpConnection {
/**
* 创建HttpConnection
- *
+ *
* @param urlStr URL
- * @param proxy 代理,无代理传{@code null}
+ * @param proxy 代理,无代理传{@code null}
* @return HttpConnection
*/
public static HttpConnection create(String urlStr, Proxy proxy) {
@@ -52,8 +50,8 @@ public class HttpConnection {
/**
* 创建HttpConnection
- *
- * @param url URL
+ *
+ * @param url URL
* @param proxy 代理,无代理传{@code null}
* @return HttpConnection
*/
@@ -62,10 +60,11 @@ public class HttpConnection {
}
// --------------------------------------------------------------- Constructor start
+
/**
* 构造HttpConnection
- *
- * @param url URL
+ *
+ * @param url URL
* @param proxy 代理
*/
public HttpConnection(URL url, Proxy proxy) {
@@ -80,7 +79,7 @@ public class HttpConnection {
/**
* 初始化连接相关信息
- *
+ *
* @return HttpConnection
* @since 4.4.1
*/
@@ -98,10 +97,11 @@ public class HttpConnection {
}
// --------------------------------------------------------------- Getters And Setters start
+
/**
* 获取请求方法,GET/POST
- *
- * @return 请求方法,GET/POST
+ *
+ * @return 请求方法, GET/POST
*/
public Method getMethod() {
return Method.valueOf(this.conn.getRequestMethod());
@@ -109,11 +109,23 @@ public class HttpConnection {
/**
* 设置请求方法
- *
+ *
* @param method 请求方法
* @return 自己
*/
public HttpConnection setMethod(Method method) {
+ if (Method.POST.equals(method) //
+ || Method.PUT.equals(method)//
+ || Method.PATCH.equals(method)//
+ || Method.DELETE.equals(method)) {
+ this.conn.setUseCaches(false);
+
+ // 增加PATCH方法支持
+ if (Method.PATCH.equals(method)) {
+ allowPatch();
+ }
+ }
+
// method
try {
this.conn.setRequestMethod(method.toString());
@@ -121,18 +133,12 @@ public class HttpConnection {
throw new HttpException(e);
}
- if (Method.POST.equals(method) //
- || Method.PUT.equals(method)//
- || Method.PATCH.equals(method)//
- || Method.DELETE.equals(method)) {
- this.conn.setUseCaches(false);
- }
return this;
}
/**
* 获取请求URL
- *
+ *
* @return 请求URL
*/
public URL getUrl() {
@@ -141,7 +147,7 @@ public class HttpConnection {
/**
* 获得代理
- *
+ *
* @return {@link Proxy}
*/
public Proxy getProxy() {
@@ -150,7 +156,7 @@ public class HttpConnection {
/**
* 获取HttpURLConnection对象
- *
+ *
* @return HttpURLConnection
*/
public HttpURLConnection getHttpURLConnection() {
@@ -160,12 +166,13 @@ public class HttpConnection {
// --------------------------------------------------------------- Getters And Setters end
// ---------------------------------------------------------------- Headers start
+
/**
* 设置请求头
* 当请求头存在时,覆盖之
- *
- * @param header 头名
- * @param value 头值
+ *
+ * @param header 头名
+ * @param value 头值
* @param isOverride 是否覆盖旧值
* @return HttpConnection
*/
@@ -184,9 +191,9 @@ public class HttpConnection {
/**
* 设置请求头
* 当请求头存在时,覆盖之
- *
- * @param header 头名
- * @param value 头值
+ *
+ * @param header 头名
+ * @param value 头值
* @param isOverride 是否覆盖旧值
* @return HttpConnection
*/
@@ -197,8 +204,8 @@ public class HttpConnection {
/**
* 设置请求头
* 不覆盖原有请求头
- *
- * @param headerMap 请求头
+ *
+ * @param headerMap 请求头
* @param isOverride 是否覆盖
* @return this
*/
@@ -217,7 +224,7 @@ public class HttpConnection {
/**
* 获取Http请求头
- *
+ *
* @param name Header名
* @return Http请求头值
*/
@@ -227,7 +234,7 @@ public class HttpConnection {
/**
* 获取Http请求头
- *
+ *
* @param name Header名
* @return Http请求头值
*/
@@ -237,7 +244,7 @@ public class HttpConnection {
/**
* 获取所有Http请求头
- *
+ *
* @return Http请求头Map
*/
public Map> headers() {
@@ -249,9 +256,9 @@ public class HttpConnection {
/**
* 设置https请求参数
* 有些时候htts请求会出现com.sun.net.ssl.internal.www.protocol.https.HttpsURLConnectionOldImpl的实现,此为sun内部api,按照普通http请求处理
- *
+ *
* @param hostnameVerifier 域名验证器,非https传入null
- * @param ssf SSLSocketFactory,非https传入null
+ * @param ssf SSLSocketFactory,非https传入null
* @return this
* @throws HttpException KeyManagementException和NoSuchAlgorithmException异常包装
*/
@@ -271,9 +278,9 @@ public class HttpConnection {
/**
* 关闭缓存
- *
+ *
* @return this
- * @see HttpURLConnection#setUseCaches(boolean)
+ * @see HttpURLConnection#setUseCaches(boolean)
*/
public HttpConnection disableCache() {
this.conn.setUseCaches(false);
@@ -282,7 +289,7 @@ public class HttpConnection {
/**
* 设置连接超时
- *
+ *
* @param timeout 超时
* @return this
*/
@@ -296,7 +303,7 @@ public class HttpConnection {
/**
* 设置读取超时
- *
+ *
* @param timeout 超时
* @return this
*/
@@ -310,7 +317,7 @@ public class HttpConnection {
/**
* 设置连接和读取的超时时间
- *
+ *
* @param timeout 超时时间
* @return this
*/
@@ -323,7 +330,7 @@ public class HttpConnection {
/**
* 设置Cookie
- *
+ *
* @param cookie Cookie
* @return this
*/
@@ -337,12 +344,12 @@ public class HttpConnection {
/**
* 采用流方式上传数据,无需本地缓存数据。
* HttpUrlConnection默认是将所有数据读到本地缓存,然后再发送给服务器,这样上传大文件时就会导致内存溢出。
- *
+ *
* @param blockSize 块大小(bytes数),0或小于0表示不设置Chuncked模式
* @return this
*/
public HttpConnection setChunkedStreamingMode(int blockSize) {
- if(blockSize > 0) {
+ if (blockSize > 0) {
conn.setChunkedStreamingMode(blockSize);
}
return this;
@@ -350,7 +357,7 @@ public class HttpConnection {
/**
* 设置自动HTTP 30X跳转
- *
+ *
* @param isInstanceFollowRedirects 是否自定跳转
* @return this
*/
@@ -361,7 +368,7 @@ public class HttpConnection {
/**
* 连接
- *
+ *
* @return this
* @throws IOException IO异常
*/
@@ -371,10 +378,10 @@ public class HttpConnection {
}
return this;
}
-
+
/**
* 静默断开连接。不抛出异常
- *
+ *
* @return this
* @since 4.6.0
*/
@@ -384,13 +391,13 @@ public class HttpConnection {
} catch (Throwable e) {
// ignore
}
-
+
return this;
}
/**
* 断开连接
- *
+ *
* @return this
*/
public HttpConnection disconnect() {
@@ -403,7 +410,7 @@ public class HttpConnection {
/**
* 获得输入流对象
* 输入流对象用于读取数据
- *
+ *
* @return 输入流对象
* @throws IOException IO异常
*/
@@ -416,7 +423,7 @@ public class HttpConnection {
/**
* 当返回错误代码时,获得错误内容流
- *
+ *
* @return 错误内容
*/
public InputStream getErrorStream() {
@@ -428,7 +435,7 @@ public class HttpConnection {
/**
* 获取输出流对象 输出流对象用于发送数据
- *
+ *
* @return OutputStream
* @throws IOException IO异常
*/
@@ -444,7 +451,7 @@ public class HttpConnection {
/**
* 获取响应码
- *
+ *
* @return 响应码
* @throws IOException IO异常
*/
@@ -459,7 +466,7 @@ public class HttpConnection {
* 获得字符集编码
* 从Http连接的头信息中获得字符集
* 从ContentType中获取
- *
+ *
* @return 字符集编码
*/
public String getCharsetName() {
@@ -470,7 +477,7 @@ public class HttpConnection {
* 获取字符集编码
* 从Http连接的头信息中获得字符集
* 从ContentType中获取
- *
+ *
* @return {@link Charset}编码
* @since 3.0.9
*/
@@ -501,10 +508,11 @@ public class HttpConnection {
}
// --------------------------------------------------------------- Private Method start
+
/**
* 初始化http或https请求参数
* 有些时候https请求会出现com.sun.net.ssl.internal.www.protocol.https.HttpsURLConnectionOldImpl的实现,此为sun内部api,按照普通http请求处理
- *
+ *
* @return {@link HttpURLConnection},https返回{@link HttpsURLConnection}
*/
private HttpURLConnection openHttp() throws IOException {
@@ -519,12 +527,30 @@ public class HttpConnection {
/**
* 建立连接
- *
+ *
* @return {@link URLConnection}
* @throws IOException IO异常
*/
private URLConnection openConnection() throws IOException {
return (null == this.proxy) ? url.openConnection() : url.openConnection(this.proxy);
}
+
+ /**
+ * 增加支持的METHOD方法
+ * see: https://stackoverflow.com/questions/25163131/httpurlconnection-invalid-http-method-patch
+ *
+ * @since 5.1.6
+ */
+ private static void allowPatch() {
+ final Field methodsField = ReflectUtil.getField(HttpURLConnection.class, "methods");
+ if (null != methodsField) {
+ // 去除final修饰
+ ReflectUtil.setFieldValue(methodsField, "modifiers", methodsField.getModifiers() & ~Modifier.FINAL);
+ final String[] methods = {
+ "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE", "PATCH"
+ };
+ ReflectUtil.setFieldValue(null, methodsField, methods);
+ }
+ }
// --------------------------------------------------------------- Private Method end
}
\ No newline at end of file
diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java b/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java
index cfcae98fe..a4d2ddd4d 100644
--- a/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java
+++ b/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java
@@ -338,13 +338,14 @@ public class HttpRequest extends HttpBase {
* @return HttpRequest
*/
public HttpRequest method(Method method) {
- if (Method.PATCH == method) {
- this.method = Method.POST;
- this.header("X-HTTP-Method-Override", "PATCH");
- } else {
- this.method = method;
- }
+// if (Method.PATCH == method) {
+// this.method = Method.POST;
+// this.header("X-HTTP-Method-Override", "PATCH");
+// } else {
+// this.method = method;
+// }
+ this.method = method;
return this;
}
diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpUtil.java b/hutool-http/src/main/java/cn/hutool/http/HttpUtil.java
index 61730c507..bd0068c99 100644
--- a/hutool-http/src/main/java/cn/hutool/http/HttpUtil.java
+++ b/hutool-http/src/main/java/cn/hutool/http/HttpUtil.java
@@ -9,14 +9,24 @@ import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.StreamProgress;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.StrBuilder;
-import cn.hutool.core.util.*;
+import cn.hutool.core.util.CharsetUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.ReUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.core.util.URLUtil;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.nio.charset.Charset;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;
diff --git a/hutool-http/src/main/java/cn/hutool/http/Method.java b/hutool-http/src/main/java/cn/hutool/http/Method.java
index ec2d7ee92..8f3ae2e13 100644
--- a/hutool-http/src/main/java/cn/hutool/http/Method.java
+++ b/hutool-http/src/main/java/cn/hutool/http/Method.java
@@ -2,8 +2,8 @@ package cn.hutool.http;
/**
* Http方法枚举
- * @author Looly
*
+ * @author Looly
*/
public enum Method {
GET, POST, HEAD, OPTIONS, PUT, DELETE, TRACE, CONNECT, PATCH
diff --git a/hutool-http/src/test/java/cn/hutool/http/test/HttpUtilTest.java b/hutool-http/src/test/java/cn/hutool/http/test/HttpUtilTest.java
index 28c0f030f..58ea75870 100644
--- a/hutool-http/src/test/java/cn/hutool/http/test/HttpUtilTest.java
+++ b/hutool-http/src/test/java/cn/hutool/http/test/HttpUtilTest.java
@@ -220,7 +220,7 @@ public class HttpUtilTest {
@Test
@Ignore
public void patchTest() {
- String body = HttpRequest.post("https://www.baidu.com").execute().body();
+ String body = HttpRequest.patch("https://www.baidu.com").execute().body();
Console.log(body);
}