Class에 선언되지 않은 필드 정보가 넘어옴(columns 필드 선언되지 않음)

org.jboss.resteasy.spi.ReaderException: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "columns"

...
Caused by: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "columns"

무시하려면

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public class .....

build.gradle

    implementation ('org.springframework.boot:spring-boot-starter-jdbc') {
        exclude group: 'com.zaxxer', module: 'HikariCP'
    }
    implementation group: 'org.apache.commons', name: 'commons-dbcp2', version: '2.9.0'

application.yaml

 

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3380/testdb
    username: root
    password: test
    dbcp2:
      initial-size: 5
      max-total: 10
      test-while-idle: true
      time-between-eviction-runs-millis: 1000
      num-tests-per-eviction-run: 1

 

[Javascript]

// https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js
// https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/pbkdf2.js

var passphrase = "key...변경";
var iv = CryptoJS.lib.WordArray.random(128/8);
var key = CryptoJS.enc.Hex.parse(CryptoJS.SHA1(passphrase).toString().substring(0,32));
console.log("key: ", key)
var ct = CryptoJS.AES.encrypt(str, key, { iv: iv });
var enc = iv.concat(ct.ciphertext).toString();

console.log("enc: ", enc)
## enc:  b3ff8dd004bb643f0aba857baccb0d45e1565d2f4a1d727c9a268580d3a2031b

console.log("Result: " + CryptoJS.AES.decrypt({
        ciphertext: CryptoJS.enc.Hex.parse(enc.substring(32))
    }, CryptoJS.enc.Hex.parse(CryptoJS.SHA1(passphrase).toString().substring(0,32)),
    {
        iv: CryptoJS.enc.Hex.parse(enc.substring(0,32)),
    }).toString(CryptoJS.enc.Utf8));
    
## Result: abcd

enc = "B8160A9EDCA2CFECE3E6444BFDE09B780D8DD2D873B93080E7F5A6F4B5644217";
console.log("JAVA 에서 암호화한 문자열 복호화 Result: " + CryptoJS.AES.decrypt({
        ciphertext: CryptoJS.enc.Hex.parse(enc.substring(32))
    }, CryptoJS.enc.Hex.parse(CryptoJS.SHA1(passphrase).toString().substring(0,32)),
    {
        iv: CryptoJS.enc.Hex.parse(enc.substring(0,32)),
    }).toString(CryptoJS.enc.Utf8));
    
## JAVA 에서 암호화한 문자열 복호화 Result: abcd

[Java]

// com.google.guava:guava:29.0-jre


import com.google.common.base.Charsets;
import com.google.common.hash.Hashing;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.security.AlgorithmParameters;
import java.util.Arrays;

public class AesCryptUtil {
    private static Logger logger = LoggerFactory.getLogger(AesCryptUtil.class);

    public static String encryptAES(String data, String secretKey) {
        try {
            byte[] secretKeys = Arrays.copyOfRange(Hashing.sha1().hashString(secretKey, Charsets.UTF_8).asBytes(), 0, 16);
            SecretKey secret = new SecretKeySpec(secretKeys, "AES");

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, secret);

            AlgorithmParameters params = cipher.getParameters();

            byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
            byte[] cipherText = cipher.doFinal(data.getBytes(Charsets.UTF_8));

            return DatatypeConverter.printHexBinary(iv) + DatatypeConverter.printHexBinary(cipherText);
        } catch (Exception e) {
            logger.error("===== exception", e);
            throw new RuntimeException(e);
        }
    }

    public static String decryptAES(String data, String secretKey) {
        try {
            byte[] secretKeys = Arrays.copyOfRange(Hashing.sha1().hashString(secretKey, Charsets.UTF_8).asBytes(), 0, 16);

            String hexedIv = data.substring(0, 32);

            String hexedCipherText = data.substring(32);

            byte[] iv = DatatypeConverter.parseHexBinary(hexedIv);
            byte[] cipherText = DatatypeConverter.parseHexBinary(hexedCipherText);

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(secretKeys, "AES"), new IvParameterSpec(iv));

            return new String(cipher.doFinal(cipherText), Charsets.UTF_8);
        }catch (Exception e) {
            logger.error("===== exception", e);
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) throws Exception {
        String key = "key...변경";


        String abcd = AesCryptUtil.encryptAES("abcd", key);
        System.out.println("enc: " + abcd);
        System.out.println("dec: " + AesCryptUtil.decryptAES(abcd, key));
        System.out.println("javascript 암호화한 문자열 복호화 dec: " + AesCryptUtil.decryptAES("b3ff8dd004bb643f0aba857baccb0d45e1565d2f4a1d727c9a268580d3a2031b", key));
    }
}

[참고] https://stackoverflow.com/questions/37368710/decrypt-aes-cbc-pkcs5padding-with-cryptojs

 

Decrypt AES/CBC/PKCS5Padding with CryptoJS

I generate 128bit AES/CBC/PKCS5Padding key using Java javax.crypto API. Here is the algorithm that I use: public static String encryptAES(String data, String secretKey) { try { byte[]

stackoverflow.com

 

 

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;

public class Test {
    public static void main(String[] args) {
        String hexString = "123 abc [0xea][0xb0][0x80][0xeb][0x82][0x98] [0xeb][0x8b][0xa4][0xeb][0x9d][0xbc]";
        do {
            hexString = hexToString(hexString); // output : 123 abc 가나 다라
        } while (hexString.indexOf("[0x") > -1);
        System.out.println("en : " + hexString);
    }
    
    private static String hexToString(String s) {
        try {
            int idx = s.indexOf("[0x");
            if (idx > -1) {
                String t = s.substring(idx, idx + 18);
                String c = new String(Hex.decodeHex(t.replaceAll("\\[0x", "").replaceAll("\\]", "").toCharArray()));
                s = s.replace(t, c);
            }
        } catch (DecoderException e) {
            throw new RuntimeException(e);
        }

        return s;
    }
}
            ## HttpClient 4.x 
            
            SSLContextBuilder builder = new SSLContextBuilder();
            builder.loadTrustMaterial(null, (certificate, authType) -> true);

            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                    builder.build(),
                    NoopHostnameVerifier.INSTANCE);

            httpClientBuilder.setSSLSocketFactory(sslsf);

유효하지 않은 인증서를 사용하는 사이트 호출 시 해결 방안

 

방법

  • HttpClient 등 모듈에서 유효한 인증서를 체크하는 로직을 예외 시키는 방법
  • certificate 인증서를 저장하여 호출하는 서버의 keystore 에 등록해주는 방법

방법 1에 대한 방법

 

방법 2에 대한 방법

  1. 크롬에서 아래와 같이 test1.cer 파일로 저장 (이름 무관)
  2. keytool -import -alias test1 -keystore  /data/tls\test1.keystore -file test1.cer -storepass changeit (alias 기존과 겹치지 않는 적당한 명칭, pass는 적당하게)
    ※ %JAVA_HOME%\jre\lib\security\cacerts 에 하지 않고 별도의 경로로 생성
  3. java 에서 https 요청 시 아래 설정 추가
    System.setProperty("javax.net.ssl.trustStore", "/data/tls/test1.keystore");

 

 

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
	at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1946)
	at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:316)
	at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:310)
	at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1639)
	at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:223)
	at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1037)
	at sun.security.ssl.Handshaker.process_record(Handshaker.java:965)
	at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1064)
	at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1395)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1379)
	at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
	at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1564)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1492)
	at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
	at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:347)
	at UrlConTest.main(UrlConTest.java:15)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:397)
	at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:302)
	at sun.security.validator.Validator.validate(Validator.java:262)
	at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
	at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
	at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
	at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1621)
	... 14 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
	at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
	at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
	at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:392)
	... 20 more

 

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;

public class TextTest {
	public static void main(String[] args) {
		Path path1 = Paths.get("test.log");
		Path path2 = Paths.get("test.log-2");

		try (Stream stream = Files.lines(path1)) {
			Files.write(path2, (Iterable)stream.filter(s->s.trim().startsWith("{")).filter(s->s.trim().endsWith("}"))::iterator);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}


json-lib, com.fasterxml.jackson 둘의 차이점을 비교해본다.

별다른 옵션 없는 심플한 상황이다.

json-lib의 경우 Object형의 NULL 변환에 문제가 있어보인다.


[JsonTest .java]

import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;

import java.io.IOException;

import org.junit.Test;

import com.fasterxml.jackson.databind.ObjectMapper;

import net.sf.json.JSONObject;
import net.sf.json.JSONSerializer;

public class JsonTest {
	@Test
	public void test_jsonlib_BeanCase() {
		try {
			TestBean inBean = new TestBean();
			inBean.setA("a Value");
			inBean.setB("");
			inBean.setC(null);
			//inBean.setD();
			
			inBean.setInt11(1);
			//inBean.setInt12();
			inBean.setInt21(1);
			inBean.setInt21(null);
			
			inBean.setBool11(true);
			//inBean.setBool12();
			inBean.setBool21(true);
			inBean.setBool21(null);
			
			JSONObject jsonObj = JSONObject.fromObject( JSONSerializer.toJSON(inBean) );
			String jsonStr = jsonObj.toString();
			System.out.println("jsonStr: " + jsonStr);
			
			jsonObj = (JSONObject) JSONObject.fromObject(jsonStr);
			TestBean outBean = (TestBean) JSONObject.toBean(jsonObj, TestBean.class);
			System.out.println(outBean);
			
			assertEquals(inBean.getA(), outBean.getA());
			assertEquals(inBean.getB(), outBean.getB());
			//assertEquals(inBean.getC(), outBean.getC());				// 문제 소지
			//assertEquals(inBean.getD(), outBean.getD());				// 문제 소지
			
			assertEquals(outBean.getC(), "");
			assertEquals(outBean.getD(), "");
			
			assertEquals(inBean.getInt11(), outBean.getInt11());
			assertEquals(inBean.getInt12(), outBean.getInt12());
			//assertEquals(inBean.getInt21(), outBean.getInt21());		// 문제 소지(아예 변환 안됨)
			//assertEquals(inBean.getInt22(), outBean.getInt22());		// 문제 소지(아예 변환 안됨)
			assertEquals(outBean.getInt21(), new Integer(0));
			assertEquals(outBean.getInt22(), new Integer(0));
			
			assertEquals(inBean.isBool11(), outBean.isBool11());
			assertEquals(inBean.isBool12(), outBean.isBool12());
			//assertEquals(inBean.getBool21(), outBean.getBool21());	// 문제 소지(아예 변환 안됨)
			//assertEquals(inBean.getBool22(), outBean.getBool22());	// 문제 소지(아예 변환 안됨)
			assertEquals(outBean.getBool21(), new Boolean(false));
			assertEquals(outBean.getBool22(), new Boolean(false));
		} catch (Exception e) {
			System.err.println("-- e: " + e);
		}
		
	}
	
	@Test
	public void test_jackson_BeanCase() {
		try {
			ObjectMapper jacksonMapper = new ObjectMapper();
			
			TestBean inBean = new TestBean();
			inBean.setA("a Value");
			inBean.setB("");
			inBean.setC(null);
			//inBean.setD();
			
			inBean.setInt11(1);
			//inBean.setInt12();
			inBean.setInt21(1);
			inBean.setInt21(null);
			
			inBean.setBool11(true);
			//inBean.setBool12();
			inBean.setBool21(true);
			inBean.setBool21(null);
			System.out.println(inBean);
			
			String jsonStr = jacksonMapper.writeValueAsString(inBean);
			System.out.println("jsonStr: " + jsonStr);
			TestBean outBean = jacksonMapper.readValue(jsonStr, TestBean.class);
			
			assertEquals(inBean.getA(), outBean.getA());
			assertEquals(inBean.getB(), outBean.getB());
			assertEquals(inBean.getC(), outBean.getC());
			assertEquals(inBean.getD(), outBean.getD());
			assertEquals(outBean.getC(), null);
			assertEquals(outBean.getD(), null);
			
			assertEquals(inBean.getInt11(), outBean.getInt11());
			assertEquals(inBean.getInt12(), outBean.getInt12());
			assertEquals(inBean.getInt21(), outBean.getInt21());
			assertEquals(inBean.getInt22(), outBean.getInt22());
			
			assertEquals(inBean.isBool11(), outBean.isBool11());
			assertEquals(inBean.isBool12(), outBean.isBool12());
			assertEquals(inBean.getBool21(), outBean.getBool21());
			assertEquals(inBean.getBool22(), outBean.getBool22());
		} catch (IOException e) {
			System.err.println("-- e: " + e);
		}
	}
}

[TestBean.java]

import lombok.Getter;
import lombok.Setter;

@Setter @Getter
public class TestBean {
	String a;
	String b;
	String c;
	String d;
	
	int int11;
	int int12;
	Integer int21;
	Integer int22;
	
	boolean bool11;
	boolean bool12;
	Boolean bool21;
	Boolean bool22;
}

[build.gradle]

sourceCompatibility='1.7'

dependencies {
    //compile group: 'commons-collections', name: 'commons-collections', version: '3.2'
    //compile 'org.apache.maven.plugins:maven-war-plugin:+'
    
    compile 'net.sf.json-lib:json-lib:2.4:jdk15@jar'
    compile 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.6.4'
    
    compile 'commons-lang:commons-lang:2.6'
    compile 'commons-logging:commons-logging:1.2'
    compile 'commons-collections:commons-collections:3.2.2'
    compile 'commons-beanutils:commons-beanutils:1.9.2'
    compile 'net.sf.ezmorph:ezmorph:1.0.6'
    
    testCompile 'junit:junit:4.11'
	testCompile 'org.hamcrest:hamcrest-all:1.3'
}


import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang.StringUtils;

// 자연수 + 공백
assertFalse(StringUtils.isNumeric(null));
assertTrue (StringUtils.isNumeric(""));
assertFalse(StringUtils.isNumeric("  "));
assertTrue (StringUtils.isNumeric("0"));
assertTrue (StringUtils.isNumeric("123"));
assertFalse(StringUtils.isNumeric("12 3"));
assertFalse(StringUtils.isNumeric("ab2c"));
assertFalse(StringUtils.isNumeric("12-3"));
assertFalse(StringUtils.isNumeric("12.3"));
assertFalse(StringUtils.isNumeric("-123"));
assertFalse(StringUtils.isNumeric("+123"));

// 자연수
assertFalse(NumberUtils.isDigits(null));
assertFalse(NumberUtils.isDigits(""));
assertFalse(NumberUtils.isDigits("  "));
assertTrue (NumberUtils.isDigits("0"));
assertTrue (NumberUtils.isDigits("123"));
assertFalse(NumberUtils.isDigits("12 3"));
assertFalse(NumberUtils.isDigits("ab2c"));
assertFalse(NumberUtils.isDigits("12-3"));
assertFalse(NumberUtils.isDigits("12.3"));
assertFalse(NumberUtils.isDigits("-123"));
assertFalse(NumberUtils.isDigits("+123"));

// 정수 + 실수 (+ 앞에 붙으면 안됨)
assertFalse(NumberUtils.isNumber(null));
assertFalse(NumberUtils.isNumber(""));
assertFalse(NumberUtils.isNumber("  "));
assertTrue (NumberUtils.isNumber("0"));
assertTrue (NumberUtils.isNumber("123"));
assertFalse(NumberUtils.isNumber("12 3"));
assertFalse(NumberUtils.isNumber("ab2c"));
assertFalse(NumberUtils.isNumber("12-3"));
assertTrue (NumberUtils.isNumber("12.3"));
assertTrue (NumberUtils.isNumber("-123"));
assertFalse(NumberUtils.isNumber("+123"));
	
		...
		
		...
	

	...

	
		
	
	
	
		
        
	

	

	
		
			
			
		
	

	...

Cluster 된 개별 WAS들이 모두 정상적으로 가동되고 있는지 모니터링 화면에서 표현해보자.


기준은 각 WAS의 Memory MBean 정보를 활용해서 WAS가 정상적인지도 체크 하고, 현재 Memory 상황은 어떤지 파악도 함께 할 수 있게 해본다.


[각각의 WAS Agent] -> vertx Net-> [모니터링 서버] -> vertx SockJs -> [Client Broswer] 방향으로 Memory 정보를 보낸다.



장애판단 기준은 WAS Agent에서 현재 5초 기준으로 모니터링 서버쪽으로 보내주고 있다.

그에 따라 Client Borswer 부분에서는 해당 정보가 (5초*1.5) 이후에도 정보가 오지 않으면 서버가 내려갔다고 판단한다.


또한 이 정보를 DB화 하여, Memory 증가량을 파악하고, GC 이후에도 Memory 가 부족하지는 않은지 판단해본다.






[MonitorAgent.java]

import java.lang.instrument.Instrumentation;
import java.util.Timer;

import pe.kr.ddakker.monitor.agent.timer.MBeanTimer;

public class MonitorAgent {
	Timer timer = new Timer("ddakker Agent Timer", true);
    Instrumentation instrumentation;
    static MonitorAgent monitorAgent;
    public static boolean isDebug = false;
	
	public static void premain(String args, Instrumentation instrumentation) throws Exception {
		
		//instrumentation.addTransformer(new TomcatTransformer());
		monitorAgent = new MonitorAgent(instrumentation);
		monitorAgent.start();
	}

	public final void start(boolean isRequest, boolean isMBean) {
		MBeanTimer mBeanTimer = new MBeanTimer();
        timer.scheduleAtFixedRate(mBeanTimer, 5000, 5000);
	}
}


[MBeanTimer.java]

import java.lang.management.ManagementFactory;
import java.util.TimerTask;

import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.openmbean.CompositeData;

import pe.kr.ddakker.monitor.agent.send.VertxClient;

public class MBeanTimer extends TimerTask {
	public void run() {
		try {
			ObjectName om = new ObjectName("java.lang:type=Memory");
			
			MBeanServer connection = ManagementFactory.getPlatformMBeanServer();
			
			
			Object attrValue = connection.getAttribute(om, "HeapMemoryUsage");
			
			long max = Long.parseLong(((CompositeData)attrValue).get("max").toString());
			long used = Long.parseLong(((CompositeData)attrValue).get("used").toString());
			long heapUsedPercent = Math.round((used*1.0 / max*1.0) * 100.0);
			
			String msg = "{name: '" + System.getProperty("jvmRoute") + "', heapUsedPercent: '" + heapUsedPercent + "', time: '" + System.currentTimeMillis() + "'}";
			msg = "{result: '0000', grp: 'grp_was', msg: '성공', data: " + msg + "}";
			
			VertxClient.send(msg);
		} catch (Exception e) {
			System.err.println();
		}

	}

}


+ Recent posts