IntelliJでローカルに実行したときに発生しない例外が、デプロイ可能なjarにヒットするという問題に直面しています。
例外:
Receiving an event {id=2, socket=0c317829-69bf-43d6-b598-7c0c550635bb, type=getDashboard, data={workstationUuid=ddec1caa-a97f-4922-833f-632da07ffc11}, reply=true}
Firing getDashboard event to Socket#0c317829-69bf-43d6-b598-7c0c550635bb
Failed invoking AtmosphereFramework.doCometSupport()
Java.lang.IllegalArgumentException: Can not deserialize instance of Java.lang.String out of START_OBJECT token
at [Source: N/A; line: -1, column: -1]
at org.codehaus.jackson.map.ObjectMapper._convert(ObjectMapper.Java:2502)
at org.codehaus.jackson.map.ObjectMapper.convertValue(ObjectMapper.Java:2468)
at com.github.flowersinthesand.portal.support.DefaultDispatcher$DefaultHandler$DataParam.resolve(DefaultDispatcher.Java:270)
at com.github.flowersinthesand.portal.support.DefaultDispatcher$DefaultHandler.handle(DefaultDispatcher.Java:204)
at com.github.flowersinthesand.portal.support.DefaultDispatcher.fire(DefaultDispatcher.Java:107)
at com.github.flowersinthesand.portal.support.AbstractSocketFactory.fire(AbstractSocketFactory.Java:73)
at com.github.flowersinthesand.portal.atmosphere.AtmosphereSocketFactory.onRequest(AtmosphereSocketFactory.Java:75)
at org.atmosphere.cpr.AsynchronousProcessor.action(AsynchronousProcessor.Java:256)
at org.atmosphere.cpr.AsynchronousProcessor.suspended(AsynchronousProcessor.Java:166)
at org.atmosphere.container.Grizzly2WebSocketSupport.service(Grizzly2WebSocketSupport.Java:75)
at org.atmosphere.cpr.AtmosphereFramework.doCometSupport(AtmosphereFramework.Java:1342)
at org.atmosphere.websocket.DefaultWebSocketProcessor.dispatch(DefaultWebSocketProcessor.Java:219)
at org.atmosphere.websocket.DefaultWebSocketProcessor$2.run(DefaultWebSocketProcessor.Java:183)
at org.atmosphere.util.VoidExecutorService.execute(VoidExecutorService.Java:101)
at org.atmosphere.websocket.DefaultWebSocketProcessor.dispatch(DefaultWebSocketProcessor.Java:178)
at org.atmosphere.websocket.DefaultWebSocketProcessor.invokeWebSocketProtocol(DefaultWebSocketProcessor.Java:167)
at org.atmosphere.container.Grizzly2WebSocketSupport$Grizzly2WebSocketApplication.onMessage(Grizzly2WebSocketSupport.Java:171)
at org.glassfish.grizzly.websockets.DefaultWebSocket.onMessage(DefaultWebSocket.Java:164)
at org.glassfish.grizzly.websockets.frametypes.TextFrameType.respond(TextFrameType.Java:70)
at org.glassfish.grizzly.websockets.DataFrame.respond(DataFrame.Java:104)
at org.glassfish.grizzly.websockets.WebSocketFilter.handleRead(WebSocketFilter.Java:221)
at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.Java:119)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.Java:265)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.Java:200)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.Java:134)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.Java:112)
at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.Java:78)
at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.Java:770)
at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.Java:112)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.Java:115)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.Java:55)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.Java:135)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.Java:551)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.Java:531)
at Java.lang.Thread.run(Thread.Java:781)
Caused by: org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of Java.lang.String out of START_OBJECT token
at [Source: N/A; line: -1, column: -1]
at org.codehaus.jackson.map.JsonMappingException.from(JsonMappingException.Java:163)
at org.codehaus.jackson.map.deser.StdDeserializationContext.mappingException(StdDeserializationContext.Java:219)
at org.codehaus.jackson.map.deser.std.StringDeserializer.deserialize(StringDeserializer.Java:44)
at org.codehaus.jackson.map.deser.std.StringDeserializer.deserialize(StringDeserializer.Java:13)
at org.codehaus.jackson.map.ObjectMapper._readValue(ObjectMapper.Java:2704)
at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.Java:1315)
at org.codehaus.jackson.map.ObjectMapper._convert(ObjectMapper.Java:2498)
... 34 more
Java.lang.IllegalArgumentException: Can not deserialize instance of Java.lang.String out of START_OBJECT token
at [Source: N/A; line: -1, column: -1] Status 500 Message Server Error
ソケットハンドラー
以下の項目が原因でJSONがWorkstationRequestオブジェクトに解析されるときに例外が発生していると思います。これはソケットハンドラです。
@On
@Reply
@JsonView({Views.WorkstationView.class})
public WorkstationDashboard getDashboard(@Data WorkstationRequest request) {
return new WorkstationDashboard(request.getWorkstation());
}
ソケットハンドラーがマップするオブジェクト:
public class WorkstationRequest {
/* Class to instantiate if this workstation does not already exist */
private Class<? extends Workstation> workstationClass;
private WorkflowProcess workflowProcess;
private PhysicalWorkstation workstation;
WorkstationService workstationService;
/**
* @param workstationClass Required so when jackson maps the UUID we can auto fetch the class
*/
public WorkstationRequest(Class<? extends Workstation> workstationClass) {
this.workstationClass = workstationClass;
workstationService = (WorkstationService) ApplicationContextProvider.getApplicationContext().getBean("workstationService");
}
/* Set the workstation based on UUID. Will register the workstation if it's new */
@JsonProperty("workstationUuid")
public void setWorkstation(String workstationUUID) {
workstation = (PhysicalWorkstation)WorkstationService.getWorkstation(workstationUUID);
//setup new workstation
if (workstation == null) {
WorkstationEntity workstationEntity = workstationService.findByUUID(workstationUUID);
workstation = (PhysicalWorkstation)Workstation.factory(workstationEntity, workstationClass);
//register with queue
WorkflowProcessService.getWorkflowProcess(workstation).registerWorkstation(workstation);
}
}
public PhysicalWorkstation getWorkstation() {
return workstation;
}
}
マッピングされるJSON:
{"id":2,"socket":"0c317829-69bf-43d6-b598-7c0c550635bb","type":"getDashboard","data":{"workstationUuid":"ddec1caa-a97f-4922-833f-632da07ffc11"},"reply":true}
WorkstationDashboard.Java
public class WorkstationDashboard {
private HashMap<String, Object> queue = new HashMap<String, Object>();
private LinkedBlockingDeque<JobSetEntity> currentWork;
public WorkstationDashboard() {
queue.put("size", 0);
}
public WorkstationDashboard(Workstation workstation) {
fromWorkstation(workstation);
}
/* Populate dashboard data from a workstation */
public void fromWorkstation(Workstation workstation) {
WorkflowProcess workflowProcess = WorkflowProcessService.getWorkflowProcess(workstation);
setCurrentWork(workstation.getCurrentWork());
setQueueSize(workflowProcess.getQueue().size());
}
public void setQueueSize(Integer queueSize) {
queue.put("size", queueSize);
}
public HashMap<String, Object> getQueue() {
return queue;
}
public LinkedBlockingDeque<JobSetEntity> getCurrentWork() {
return currentWork;
}
public void setCurrentWork(LinkedBlockingDeque<JobSetEntity> currentWork) {
this.currentWork = currentWork;
}
}
これのデバッグを開始する方法について私はかなり迷っています。スタックトレースがアプリケーションに影響することはありません。 Maven -> Package
を使用して.jarをデプロイし、Java -jar /path-to-jar.jar
で実行しています
更新:この質問が非常に長くなるのを防ぐために、pom.xmlをここに含めました: http://Pastebin.com/1ZUtKCfE 。このエラーはローカルPCではなくデプロイ可能なjarでのみ発生するため、これは依存関係の問題だと思います。
このJSONをマッピングしています
{
"id": 2,
"socket": "0c317829-69bf-43d6-b598-7c0c550635bb",
"type": "getDashboard",
"data": {
"workstationUuid": "ddec1caa-a97f-4922-833f-632da07ffc11"
},
"reply": true
}
値としてJSONオブジェクトを持つdata
という名前の要素が含まれます。 workstationUuid
という名前の要素をそのJSONオブジェクトからこのセッターにデシリアライズしようとしています。
@JsonProperty("workstationUuid")
public void setWorkstation(String workstationUUID) {
Jacksonは文字列ではなくJSON_OBJECTを認識するため、これは直接機能しません。
クラスを作成してみてくださいData
public class Data { // the name doesn't matter
@JsonProperty("workstationUuid")
private String workstationUuid;
// getter and setter
}
メソッドを切り替える
@JsonProperty("data")
public void setWorkstation(Data data) {
// use getter to retrieve it
データ内容は非常に可変的であるため、「ObjectNode」として定義し、次に解析する独自のクラスを作成するのが最良の形式だと思います。
最後に:
プライベートObjectNodeデータ。
ネストされたjsonの別のクラスを定義したくない場合、ネストされたjsonオブジェクトをJsonNodeとして定義することで動作します。たとえば、
{"id":2,"socket":"0c317829-69bf-43d6-b598-7c0c550635bb","type":"getDashboard","data":{"workstationUuid":"ddec1caa-a97f-4922-833f-632da07ffc11"},"reply":true}
@JsonProperty("data")
private JsonNode data;
この方法で問題を解決しました。それが他の人を助けることを願っています。私の場合、クラス、フィールド、それらのゲッターとセッターを作成し、文字列の代わりにオブジェクトを提供します。
これを使用
public static class EncryptedData {
private String encryptedData;
public String getEncryptedData() {
return encryptedData;
}
public void setEncryptedData(String encryptedData) {
this.encryptedData = encryptedData;
}
}
@PutMapping(value = MY_IP_ADDRESS)
public ResponseEntity<RestResponse> updateMyIpAddress(@RequestBody final EncryptedData encryptedData) {
try {
Path path = Paths.get(PUBLIC_KEY);
byte[] bytes = Files.readAllBytes(path);
PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(base64.decode(bytes));
PrivateKey privateKey = KeyFactory.getInstance(CRYPTO_ALGO_RSA).generatePrivate(ks);
Cipher cipher = Cipher.getInstance(CRYPTO_ALGO_RSA);
cipher.init(Cipher.PRIVATE_KEY, privateKey);
String decryptedData = new String(cipher.doFinal(encryptedData.getEncryptedData().getBytes()));
String[] dataArray = decryptedData.split("|");
Method updateIp = Class.forName("com.cuanet.client.helper").getMethod("methodName", String.class,String.class);
updateIp.invoke(null, dataArray[0], dataArray[1]);
} catch (Exception e) {
LOG.error("Unable to update ip address for encrypted data: "+encryptedData, e);
}
return null;
これの代わりに
@PutMapping(value = MY_IP_ADDRESS)
public ResponseEntity<RestResponse> updateMyIpAddress(@RequestBody final EncryptedData encryptedData) {
try {
Path path = Paths.get(PUBLIC_KEY);
byte[] bytes = Files.readAllBytes(path);
PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(base64.decode(bytes));
PrivateKey privateKey = KeyFactory.getInstance(CRYPTO_ALGO_RSA).generatePrivate(ks);
Cipher cipher = Cipher.getInstance(CRYPTO_ALGO_RSA);
cipher.init(Cipher.PRIVATE_KEY, privateKey);
String decryptedData = new String(cipher.doFinal(encryptedData.getBytes()));
String[] dataArray = decryptedData.split("|");
Method updateIp = Class.forName("com.cuanet.client.helper").getMethod("methodName", String.class,String.class);
updateIp.invoke(null, dataArray[0], dataArray[1]);
} catch (Exception e) {
LOG.error("Unable to update ip address for encrypted data: "+encryptedData, e);
}
return null;
}
Jacksonライブラリを使用して問題を解決しました。プリントはメインクラスから呼び出され、すべてのPOJOクラスが作成されます。コードスニペットを次に示します。
MainClass.Java
public class MainClass {
public static void main(String[] args) throws JsonParseException,
JsonMappingException, IOException {
String jsonStr = "{\r\n" + " \"id\": 2,\r\n" + " \"socket\": \"0c317829-69bf-
43d6-b598-7c0c550635bb\",\r\n"
+ " \"type\": \"getDashboard\",\r\n" + " \"data\": {\r\n"
+ " \"workstationUuid\": \"ddec1caa-a97f-4922-833f-
632da07ffc11\"\r\n" + " },\r\n"
+ " \"reply\": true\r\n" + "}";
ObjectMapper mapper = new ObjectMapper();
MyPojo details = mapper.readValue(jsonStr, MyPojo.class);
System.out.println("Value for getFirstName is: " + details.getId());
System.out.println("Value for getLastName is: " + details.getSocket());
System.out.println("Value for getChildren is: " +
details.getData().getWorkstationUuid());
System.out.println("Value for getChildren is: " + details.getReply());
}
MyPojo.Java
public class MyPojo {
private String id;
private Data data;
private String reply;
private String socket;
private String type;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Data getData() {
return data;
}
public void setData(Data data) {
this.data = data;
}
public String getReply() {
return reply;
}
public void setReply(String reply) {
this.reply = reply;
}
public String getSocket() {
return socket;
}
public void setSocket(String socket) {
this.socket = socket;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
Data.Java
public class Data {
private String workstationUuid;
public String getWorkstationUuid() {
return workstationUuid;
}
public void setWorkstationUuid(String workstationUuid) {
this.workstationUuid = workstationUuid;
}
}
結果:
getFirstNameの値:2 getLastNameの値:0c317829-69bf-43d6-b598-7c0c550635bb getChildrenの値:ddec1caa-a97f-4922-833f-632da07ffc11 getChildrenの値:true