diff --git a/src/main/java/cokr/xit/foundation/data/JSON.java b/src/main/java/cokr/xit/foundation/data/JSON.java
index 406b158..177ce3b 100644
--- a/src/main/java/cokr/xit/foundation/data/JSON.java
+++ b/src/main/java/cokr/xit/foundation/data/JSON.java
@@ -1,9 +1,15 @@
package cokr.xit.foundation.data;
import java.io.InputStream;
+import java.util.Set;
import com.fasterxml.jackson.core.JsonParser.Feature;
+import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectWriter;
+import com.fasterxml.jackson.databind.ser.FilterProvider;
+import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
+import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import cokr.xit.foundation.AbstractComponent;
@@ -12,6 +18,7 @@ import cokr.xit.foundation.AbstractComponent;
*/
public class JSON extends AbstractComponent {
private ObjectMapper objectMapper;
+ private FilterProvider filterProvider;
/**JSON 포맷/파싱에 사용하는 ObjectMapper를 반환한다.
* @return JSON 포맷/파싱에 사용하는 ObjectMapper
@@ -20,6 +27,7 @@ public class JSON extends AbstractComponent {
if (objectMapper == null) {
objectMapper = new ObjectMapper();
objectMapper.configure(Feature.ALLOW_COMMENTS, true);
+ objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
return objectMapper;
}
@@ -33,6 +41,15 @@ public class JSON extends AbstractComponent {
return this;
}
+ /**객체를 JSON 문자열로 변환할 때 적용할 Filter를 반환한다.
+ * 이 때 객체의 클래스는 {@code @JsonFilter("필터 아이디")} 주석이 적용되어 있어야 한다.
+ * @param id 필터 아이디
+ * @return Filter
+ */
+ public Filter filter(String id) {
+ return new Filter().init(id, this);
+ }
+
/**JSON 문자열을 파싱하여 주어진 클래스의 객체로 변환한다.
* @param 클래스 유형
* @param json JSON 문자열
@@ -80,10 +97,81 @@ public class JSON extends AbstractComponent {
public String stringify(Object obj, boolean indent) {
if (obj instanceof String)
return (String)obj;
+
+ ObjectMapper mapper = getObjectMapper();
+ ObjectWriter writer = null;
+ if (!indent) {
+ writer = filterProvider == null ? mapper.writer() : mapper.writer(filterProvider);
+ } else {
+ writer = mapper.writerWithDefaultPrettyPrinter();
+ if (filterProvider != null)
+ writer = writer.with(filterProvider);
+ }
+
try {
- return getObjectMapper().writeValueAsString(obj);
+ return writer.writeValueAsString(obj);
} catch (Exception e) {
throw runtimeException(e);
}
}
+
+ /**객체를 JSON 문자열로 변환할 때 적용할 필터 설정을 지원하는 클래스.
+ * 이 때 객체의 클래스는 {@code @JsonFilter("필터 아이디")} 주석이 적용되어 있어야 한다.
+ * @author mjkhan
+ */
+ public static class Filter {
+ private String id;
+ private JSON json;
+
+ private Filter init(String id, JSON json) {
+ this.id = id;
+ this.json = json;
+ return this;
+ }
+
+ /**JSON 문자열로 변환할 때 포함시킬 객체의 프로퍼티 이름을 설정한다.
+ * 빈 값을 설정하면 모든 프로퍼티를 포함시킨다.
+ * @param properties JSON 문자열에 포함시킬 객체의 프로퍼티 이름
+ * @return JSON
+ */
+ public JSON include(Set properties) {
+ return setProvider(!isEmpty(properties) ?
+ SimpleBeanPropertyFilter.filterOutAllExcept(properties) :
+ SimpleBeanPropertyFilter.serializeAll()
+ );
+ }
+
+ /**JSON 문자열로 변환할 때 포함시킬 객체의 프로퍼티 이름을 설정한다.
+ * 빈 값을 설정하면 모든 프로퍼티를 포함시킨다.
+ * @param properties JSON 문자열에 포함시킬 객체의 프로퍼티 이름
+ * @return JSON
+ */
+ public JSON include(String... properties) {
+ return include(Set.of(properties));
+ }
+
+ /**JSON 문자열로 변환할 때 제외할 객체의 프로퍼티 이름을 설정한다.
+ * @param properties JSON 문자열에서 제외할 객체의 프로퍼티 이름
+ * @return JSON
+ */
+ public JSON exclude(Set properties) {
+ notEmpty(properties, "properties");
+ return setProvider(SimpleBeanPropertyFilter.serializeAllExcept(properties));
+ }
+
+ /**JSON 문자열로 변환할 때 제외할 객체의 프로퍼티 이름을 설정한다.
+ * @param properties JSON 문자열에서 제외할 객체의 프로퍼티 이름
+ * @return JSON
+ */
+ public JSON exclude(String... properties) {
+ return exclude(Set.of(properties));
+ }
+
+ private JSON setProvider(SimpleBeanPropertyFilter filter) {
+ SimpleFilterProvider provider = new SimpleFilterProvider();
+ provider.addFilter(id, filter);
+ json.filterProvider = provider;
+ return json;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/main/java/cokr/xit/foundation/web/WebClient.java b/src/main/java/cokr/xit/foundation/web/WebClient.java
index dbf0716..d921cca 100644
--- a/src/main/java/cokr/xit/foundation/web/WebClient.java
+++ b/src/main/java/cokr/xit/foundation/web/WebClient.java
@@ -26,6 +26,8 @@ import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
+import javax.net.ssl.SSLContext;
+
import cokr.xit.foundation.Assert;
import cokr.xit.foundation.data.JSON;
@@ -83,6 +85,7 @@ public class WebClient {
private HttpClient.Version version = HttpClient.Version.HTTP_2;
private Duration timeout = Duration.ofSeconds(30);
private Authenticator authenticator;
+ private SSLContext sslContext;
private ProxySelector proxy;
private HttpClient.Redirect followRedirects = HttpClient.Redirect.NORMAL;
@@ -114,6 +117,15 @@ public class WebClient {
return this;
}
+ /**SSL 통신을 할 경우 SSLContext를 설정한다.
+ * @param sslContext SSLContext
+ * @return 현재 WebClient
+ */
+ public WebClient sslContext(SSLContext sslContext) {
+ this.sslContext = sslContext;
+ return this;
+ }
+
/**서버와 접속 시 프록시를 사용할 경우 proxy를 설정한다.
* @param proxy 서버 접속에 사용할 프록시 설정
* @return 현재 WebClient
@@ -140,6 +152,8 @@ public class WebClient {
if (authenticator != null)
builder.authenticator(authenticator);
+ if (sslContext != null)
+ builder.sslContext(sslContext);
if (proxy != null)
builder.proxy(proxy);
@@ -241,6 +255,9 @@ public class WebClient {
* @author mjkhan
*/
public static class Request {
+ /** 요청 성공 */
+ public static final int SUCCESS = 200;
+
public static enum ContentType {
FORM("application/x-www-form-urlencoded"),
JSON("application/json"),
@@ -272,6 +289,8 @@ public class WebClient {
private Charset charset = StandardCharsets.UTF_8;
private LinkedHashMap headers;
private LinkedHashMap keyValues;
+
+ private JSON json;
private Consumer> textHandler = hresp -> {
HttpHeaders headers = hresp.headers();
headers.map().forEach((k, v) -> System.out.println(k + " = " + v));
@@ -340,17 +359,18 @@ public class WebClient {
return this;
}
- /**데이터를 JSON으로 주고받는지 설정한다. 디폴트는 false.
- * @param json 데이터의 JSON 여부
- * - 데이터를 JSON으로 주고받으면 true
- * - 그렇지 않으면 false
- *
+ /**데이터를 JSON으로 변환할 JSON을 설정한다.
+ * @param json JSON
* @return 현재 Request
- public Request json(boolean json) {
+ */
+ public Request json(JSON json) {
this.json = json;
- return this;
+ return contentType(ContentType.JSON);
+ }
+
+ private JSON json() {
+ return Assert.ifEmpty(json, () -> json = new JSON());
}
- */
/**요청의 응답이 파일인지 설정한다. 디폴트는 false(텍스트).
* @param download
@@ -365,7 +385,8 @@ public class WebClient {
}
private Object bodyData() {
- if (Assert.isEmpty(keyValues)) return null;
+ int size = keyValues != null ? keyValues.size() : 0;
+ if (size != 1) return null;
Object value = keyValues.remove("body");
if (value != null)
@@ -448,10 +469,10 @@ public class WebClient {
private String inJSON() {
Object body = bodyData();
if (!Assert.isEmpty(body))
- return new JSON().stringify(body);
+ return json().stringify(body);
if (!Assert.isEmpty(keyValues))
- return new JSON().stringify(keyValues);
+ return json().stringify(keyValues);
return "";
}