Based on creating a chat application, I wrote an article about WebSocket communication between the server and the browser. Implement the server in Java and the client in javascript.
[Past articles on socket communication] ・ Socket communication with web browser using Java and JavaScript ① ・ Socket communication with web browser using Java and JavaScript②
This time, we will learn about "how to handle JSON data" while modifying the chat application. You will also learn about "sending and receiving JSON data via socket communication".
In this article, I will mainly describe how to handle JSON. For an explanation of socket communication, please refer to past articles and googled pages. ⇒ Implement the server program in Java and the client program in JavaScript.
http://www.tohoho-web.com/ex/json.html
Example: {" name ":" Tanaka "," age ": 26}
A thing that holds values in the form of an associative array.
In short, it is easy to understand if you think of it as a ** just a character string **. (Although not really)
Details are omitted.
JSON data can be easily handled in JavaScript.
Object ⇒ JSON
Use the JSON.stringify ()
method.
Example of use
var obj = {
name: 'Taro',
age: 30,
area: 'Tokyo'
}
var json = JSON.stringify(obj);
console.log(json);
Execution result
{"name":"Taro Tanaka","age":30}
JSON.stringify (obj)
and assign it to the variable json
. (Convert to JSON)console.log (json)
.Looking at the execution result, you can see that the object in associative array format has been converted to JSON format. ⇒Keys and character strings are enclosed in "" ". The numbers remain naked.
JSON ⇒ object
Use the JSON.parse ()
method.
Example of use
var obj1 = {
name: 'Taro',
age: 30,
area: 'Tokyo'
}
var json = JSON.stringify(obj1);
//-----JSON data preparation so far-----
var obj2 = JSON.parse(json);
console.log(obj2);
console.log(obj2.name);
Execution result
{name: "Taro", age: 30, area: "Tokyo"}
Taro
JSON.stringify (obj1)
and assign it to the variable json
. (Convert to JSON)
** ---------- So far JSON data preparation (same as encoding in the previous section) ---------- **JSON.parse (json)
and assign it to the variable ʻobj2`. (Convert to object)console.log (obj2)
.Looking at the execution result, you can see that the JSON data has been converted to an object.
ʻObj1 (object) ⇒
json (JSON) ⇒ ʻobj2
(object)
Java objects refer to classes and are not as easy to create as JavaScript. When converting JSON and objects, it is necessary to create a class ** that has properties corresponding to JSON variables in advance.
If you handle JSON in Java, it is recommended to use an external library. ⇒ Java standard API that handles JSON is also available, but it takes a lot of time and effort.
The following are famous external libraries that handle JSON.
The basic usage is similar, but this time I will use "Jackson". For information on how to use other libraries and how to apply external libraries, see the reference page or google as appropriate.
Object ⇒ JSON
Use the writeValueAsString ()
method of the ʻObjectMapper` class for encoding.
how to use
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(Object instance);
Example of use
import java.io.IOException;
import com.fasterxml.jackson.databind.ObjectMapper;
//A class with properties to convert to JSON
class Info {
public String name = "Taro Tanaka";
public int age = 30;
}
//Class to perform encoding
public class Main {
public static void main(String[] args) {
Info info = new Info();//Instantiate a class to convert to JSON
ObjectMapper mapper = new ObjectMapper();//Create an instance of the ObjectMapper class
try {
//writeValueAsString()Encoding by method
String script = mapper.writeValueAsString(info);
System.out.println(script);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Execution result
{"name":"Taro Tanaka","age":30}
Main
class to perform the encoding. class with
ObjectMapper mapper = new ObjectMapper () `.mapper.writeValueAsString (info)
.
At this time, it is necessary to deal with errors with try and catch.System.out.println (script)
.Looking at the execution result, you can see that the object class has been converted to JSON format. The variable name and value of each property are stored as a pair.
JSON ⇒ object
Use the readValue ()
method of the ʻObjectMapper` class for decoding.
how to use
ObjectMapper mapper = new ObjectMapper();
mapper.readValue(JSON data,Object class.class);
Example of use
import java.io.IOException;
import com.fasterxml.jackson.databind.ObjectMapper;
//A class with properties that are converted from JSON
class Info {
public String name;
public int age;
}
//Class to perform decoding
public class Main {
public static void main(String[] args) {
String script = "{ \"name\":\"Taro Tanaka\", \"age\":30}";//Create JSON data as a string
ObjectMapper mapper = new ObjectMapper();//Create an instance of the ObjectMapper class
try {
//readValue()Decoding by method
Info info = mapper.readValue(script, Info.class);
System.out.println(info.name);
System.out.println(info.age);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Execution result
Taro Tanaka
30
Main
class to perform the decoding. class with
ObjectMapper mapper = new ObjectMapper () `.mapper.readValue (script, Info.class)
.
At this time, it is necessary to deal with errors with try and catch.System.out.println (info. ~)
.Looking at the execution result, you can see that the JSON data has been converted to the object class. After decoding, the value can be obtained by accessing each property of the specified object.
Server program: Java Client program: JavaScript
Describe the method of sending and receiving in JSON when performing socket communication. Since the handling is different between Java and JavaScript, we will explain each.
There is nothing special about JavaScript.
As mentioned above, you can easily convert between object and JSON with the JSON.stringify ()
method and the JSON.parse ()
method.
There is no problem if the client encodes before sending and decodes after receiving.
Object ⇒ JSON
When sending
var obj = { type:'A' , msg:'a' };
var json = JSON.stringify(obj);
socket.send(json);
JSON.stringify ()
method.send ()
method of WebSocketJSON ⇒ object
When receiving
socket.onmessage = function(e) {
var obj = JSON.parse(e.data);
};
JSON.parse (e.data)
When using JSON for Java socket communication, it is not as easy as JavaScript. ⇒ It is necessary to prepare an encoder, a decoder, and an object class.
Object ⇒ JSON
When sending JSON data by socket communication, convert the object to JSON using an encoder before sending.
Normally, the sendText ()
method is used when sending text data, but the sendObject ()
method is used when sending JSON.
The argument is an object, converted to JSON by the encoder, and then sent.
Create a class with properties like a normal class. Describe the constructor, setter, and getter as usual. (Can be converted without it.)
Object class
public class JsonObj {
private String type = "type1";
private String msg = "msg1";
//constructor
public JsonObj() {}
//Setter
public void setType(String type) {this.type = type;}
public void setMsg(String msg) {this.msg = msg;}
//Getter
public String getType() {return type;}
public String getMsg() {return msg;}
}
The encoder implements the ʻEncoder.Text class in the
javax.websocket package. (There is also the ʻEncoder.Binary
class, but it is omitted because it is a class for handling binary data)
ʻEncoder.Text <> `generics describes the object class to encode.
encoder
import javax.websocket.EncodeException;
import javax.websocket.Encoder;
import javax.websocket.EndpointConfig;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JsonEncoder implements Encoder.Text<JsonObj>{
@Override//Initialization does nothing
public void init(EndpointConfig config) {}
@Override//Encoding process(Object → JSON)
public String encode(JsonObj obj) throws EncodeException {
ObjectMapper mapper = new ObjectMapper();
String json = "";
try {
json = mapper.writeValueAsString(obj);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return json;
}
@Override//Do nothing to destroy
public void destroy() {}
}
ʻIf you inherit the Encoder.Text` class, you need to override the following methods.
destroy ()
: Processing when the encoder is destroyed.Basically ʻinit ()and
destroy () do not have to do anything. In ʻencode (Object)
, set ** argument to object ** and specify JSON ** as return value after encoding.
@ServerEndpoint
//Specify encoder class
@ServerEndpoint(value = "/json" , encoders = JsonEncoder.class)
public class JsonTest {
//Omission
//sendObject()The argument of is an object
//Encoded before sending
session.getAsyncRemote().sendObject(obj)
//Omission
}
When using an encoder, specify the encoder class in @ServerEndpoint ()
.
By specifying here, it will be converted to JSON data by the encoder specified when sending the object.
--sendObject (obj)
** ⇒ Encoding process (obj → JSON) ⇒ Send **
JSON ⇒ object
When receiving JSON data by socket communication, use a decoder to convert JSON to an object before receiving it.
Normally, it is received as a String type character string as an argument of the ʻonMessage ()` method, but by using a decoder, decoding processing is performed before reception and it is received as an object.
When decoding, it is necessary to prepare an object class that has properties corresponding to JSON elements. If the content and format are different when receiving multiple JSON, you must prepare multiple object classes corresponding to each JSON.
In the case of encoding, all objects can be converted to JSON and sent at any time In the case of decoding, it is necessary to grasp the contents of the received JSON in advance and prepare the object class to be the receiving port before decoding.
Object class
public class JsonObj {
private String type;
private String msg;
//constructor
public JsonObj() {}
//Setter
public void setType(String type) {this.type = type;}
public void setMsg(String msg) {this.msg = msg;}
//Getter
public String getType() {return type;}
public String getMsg() {return msg;}
}
The decoder implements the Decoder.Text
class in the javax.websocket
package.
(There is also a Decoder.Binary
class, but it is omitted because it is a class for handling binary data.)
Describe the object class of the decoding destination in the generics of Decoder.Text <>
.
Decoder
import javax.websocket.DecodeException;
import javax.websocket.Decoder;
import javax.websocket.EndpointConfig;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JsonDecoder implements Decoder.Text<JsonObj> {
@Override//Initialization does nothing
public void init(EndpointConfig config) {}
@Override//Judgment of whether decoding is possible
public boolean willDecode(String text) {
return (text != null);
}
@Override//Decoding process(JSON → object)
public JsonObj decode(String text) throws DecodeException {
ObjectMapper mapper = new ObjectMapper();
JsonObj obj = null;
try {
obj = mapper.readValue(text, JsonObj.class);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return obj;
}
@Override//Do nothing to destroy
public void destroy() {}
}
If you inherit the Decoder.Text
class, you need to override the following methods.
willDecode (String text)
: Judgment whether to execute decoding process.decode (Object obj)
: Decoding process.destroy ()
: Processing when the decoder is destroyed.Basically ʻinit ()and
destroy ()do not have to do anything. Set the ** argument of
willDecode ()to JSON **, and if the return value is
true, execute the following decoding. If it is
false, it will not be decoded and the subsequent
@ OnMessagemethods will not be executed. In
decode ()`, set ** argument to JSON ** and specify object ** as return value after encoding.
@ServerEndpoint
//Specify decoder class
@ServerEndpoint(value = "/json" , decoders = JsonDecoder.class)
public class JsonTest {
//Omission
//@Decoded before the OnMessage method
@OnMessage
public void onMessage(JsonObj obj , Session mySession) {
}
//Omission
}
When using a decoder, specify the decoder class in @ServerEndpoint ()
.
By specifying here, it will be converted to an object by the decoder specified at the time of data reception.
⇒ The argument of the @OnMessage
method is ** object type **. (Usually String type)
-** Receive ⇒ Decode process (JSON → obj) ⇒ ** @OnMessage
** Method **
Modify the chat app created in Past.
In WebSocket communication, there is only one socket for receiving data. In other words, because it is a one-pass, it is indistinguishable even if there are multiple sources. If you can tell, you have to break down the contents of the string to distinguish them. If you want to decode anyway, it is convenient to handle JSON.
Actually, there are three types of receiving methods: 1. Text 2. Binary 3. PingPong, but since we only handle text format here, we consider that there is only one socket.
JsonIndex.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Send / receive JSON</title>
<script type="text/javascript" src="JsonSocket.js"></script>
</head>
<body>
<div
style="width: 500px; height: 200px; overflow-y: auto; border: 1px solid #333;"
id="show1"></div>
<input type="text" size="80" id="msg1" name="msg1" />
<input type="button" value="Send" onclick="sendMsg1();" />
<p></p>
<div
style="width: 500px; height: 200px; overflow-y: auto; border: 1px solid #333;"
id="show2"></div>
<input type="text" size="80" id="msg2" name="msg2" />
<input type="button" value="Send" onclick="sendMsg2();" />
</body>
</html>
point
show1
and show2
, and the text boxes are msg1
and msg2
, respectively.
Operate these with the JavaScript file described later.JsonSocket.js
//Object creation for JSON
var obj = { type:null , msg:null };
//WebSocket object generation
var wSck= new WebSocket("ws://localhost:8080/jsonTest/json");
//Action when connecting socket
wSck.onopen = function() {
document.getElementById('show1').innerHTML += "Connected." + "<br/>";
document.getElementById('show2').innerHTML += "I'm connected ~" + "<br/>";
};
//Action when receiving a message
wSck.onmessage = function(e) {
//Decode JSON data into an object
var json = JSON.parse(e.data);
//Change the execution content depending on the type value of JSON data
if(json.type === 'msg1'){document.getElementById('show1').innerHTML += json.msg + "<br/>";}
else if(json.type === 'msg2'){document.getElementById('show2').innerHTML += json.msg + "<br/>";}
};
//Send message 1
var sendMsg1 = function(val) {
var element = document.getElementById('msg1')
obj.type = element.name;//Substitute the contents of the object
obj.msg = element.value;
var json = JSON.stringify(obj);//Encode object to JSON
wSck.send(json);//Send JSON
element.value = "";//Clear the contents
};
//Send message 2
var sendMsg2 = function(val) {
var element = document.getElementById('msg2');
obj.type = element.name;
obj.msg = element.value;
var json = JSON.stringify(obj);
wSck.send(json);
element.value = "";
};
point
JsonTest.java
package jsonTest;
import java.io.IOException;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
//Describe the decoder and encoder in the arguments
@ServerEndpoint(value = "/json" , decoders = JsonDecoder.class , encoders = JsonEncoder.class)
public class JsonTest {
private static Set<Session> user = new CopyOnWriteArraySet<>();
@OnOpen
public void onOpen(Session mySession) {
System.out.println("connect ID:"+mySession.getId());
user.add(mySession);
}
//Decoded before this method
@OnMessage
public void onMessage(JsonObj obj , Session mySession) {
for (Session user : user) {
user.getAsyncRemote().sendObject(obj);//What you send is an object(Encoded before sending)
System.out.println(user.getId()+"Second"+mySession.getId()+"I sent the second message!");
}
if(obj.getMsg().equals("bye")) {onClose(mySession);}
}
@OnClose
public void onClose(Session mySession) {
System.out.println("disconnect ID:"+mySession.getId());
user.remove(mySession);
try {
mySession.close();
} catch (IOException e) {
System.err.println("An error has occurred: " + e);
}
}
}
point
@ServerEndpoint
.@OnMesaage
method is executed and JSON will be converted to an object.
⇒ The argument of the @OnMesaage
method is of type ʻObj`.sendObject (obj)
method, the specified encoder is executed before sending to the client and the object is converted to JSON.sendText ()
when sending a character string, but use sendObject ()
when sending an object.JsonObj.java
package jsonTest;
public class JsonObj {
private String type;
private String msg;
//constructor
public JsonObj() {}
//Setter
public void setType(String type) {this.type = type;}
public void setMsg(String msg) {this.msg = msg;}
//Getter
public String getType() {return type;}
public String getMsg() {return msg;}
}
point
type
and msg
.
⇒ A class corresponding to the client program object (received JSON) is created.type
property value.JsonEncoder.java
package jsonTest;
import javax.websocket.EncodeException;
import javax.websocket.Encoder;
import javax.websocket.EndpointConfig;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JsonEncoder implements Encoder.Text<JsonObj>{
@Override//Initialization does nothing
public void init(EndpointConfig config) {}
@Override//Encoding process(Object → JSON)
public String encode(JsonObj obj) throws EncodeException {
ObjectMapper mapper = new ObjectMapper();
String json = "";
try {
json = mapper.writeValueAsString(obj);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return json;
}
@Override//Do nothing to destroy
public void destroy() {}
}
point
writeValueAsString ()
method of the ʻObjectMapper` class for encoding.package jsonTest;
import javax.websocket.DecodeException;
import javax.websocket.Decoder;
import javax.websocket.EndpointConfig;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JsonDecoder implements Decoder.Text<JsonObj> {
@Override//Initialization does nothing
public void init(EndpointConfig config) {}
@Override//Judgment of whether decoding is possible
public boolean willDecode(String text) {
return (text != null);
}
@Override//Decoding process(JSON → object)
public JsonObj decode(String text) throws DecodeException {
ObjectMapper mapper = new ObjectMapper();
JsonObj obj = null;
try {
obj = mapper.readValue(text, JsonObj.class);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return obj;
}
@Override//Do nothing to destroy
public void destroy() {}
}
point
Decoder.Text <JsonObj>
.decode ()
method is a string (JSON), and the return value is an object.readValue ()
method of the ʻObjectMapper` class for encoding.Execute JsonIndex.html
in Chrome.
The chat field has been increased to two. You can send and receive independently in each chat field. ⇒ Realization of multiple paths is completed.
Now that it's long, describe what's happening on the client and server.
@OnMessage
method with the decoded object as an argument.sendObject ()
method.type
property value and display a message to each source.-If unknown JSON data is received, an error will occur because the corresponding object class is not prepared. ⇒There are people who support it, so I may check it soon. It looks pretty complicated.
-Not supported when receiving JSON data of multiple types. ⇒ It doesn't seem that difficult. It can be done by increasing the decoder and object class to support the contents of JSON.
-It is unknown what kind of object class should be created to support nested JSON. ⇒ If you google, it will come out, and if necessary, check it.
-Since the handling of binary data is not well understood, it does not support sending and receiving of binary data. ⇒Check if necessary, such as sending and receiving images.
It was more complicated than I expected. I regret it because it has become long. I should have summarized more.
To handle JSON in Java, it is troublesome to use an external library and prepare an object class. With JavaScript, it ends in one line.
When dealing with JSON in Java socket communication, is it convenient to have an encoding class and a decoding class? It is troublesome to have to prepare an encoder class and a decoder class.
It's a hassle, but if you want to use JSON, you can't help it. It was good to have a deeper understanding of how to handle JSON in Java. It seems that you can use it at the personal production level.
-Encoding and decoding JSON data with JavaScript -Encoding and decoding JSON data in Java (Jackson) -Encoding and decoding JSON data in Java (Jackson specialization) -Encoding and decoding JSON data in Java (Jackson et al.) -Send / Receive JSON in Socket Communication -Send / Receive JSON in Socket Communication (Multi-Object)
Recommended Posts