웹 개발 과정에서 데이터 상호 작용은 필수 불가결하며, 이는 클라이언트와 서버간에 데이터를 전달할 수 있도록 관련 형식의 대화식 데이터를 지정해야합니다. 일반적으로 두 가지 유형의 데이터 형식이 있습니다 : 1. XML; 2. JSON. 일반적으로 JSON은 데이터를 전달하는 데 사용됩니다. 이 기사에서는 JSON과 Java에서 객체를 변환 할 때 발생하는 몇 가지 문제와 관련 제안을 소개합니다.
먼저 JSON에 대한 두 가지 개념이 있습니다.
JSON 객체 (JavaScript 객체 표기법, JavaScript 객체 표기법). 이것은 사용자 정의 JavaScript 비트 인 것처럼 보이지만 구문과 같은 언어 및 플랫폼 별입니다. 그것은 일반적으로 데이터를 서버 측 (브라우저)로 전달할 때 JSON 형식을 사용 하며이 형식은 JavaScript 객체를 나타내는 데 사용됩니다. { "id": 1, "name": "Kevin"}과 같은 일련의 "key values"로 구성되며, 이는 MAP 키 값 쌍이 저장되는 방식과 다소 유사합니다. Java에 설명 된 JSON 객체는 실제로 JsonObject 클래스를 나타냅니다.이 클래스는 일반적으로 각 타사 JSONJAR 패키지 에서이 이름의 이름을 따서 명명됩니다. 다른 JAR 패키지마다 약간 다른 내부 구현이 있습니다.
JSON 문자열. JSON 객체와 JSON 문자열 사이의 변환은 직렬화 및 사막화 과정으로, Java 객체의 직렬화 및 사막화와 같습니다. 네트워크의 데이터 전송은 문자열 또는 바이너리 스트림 등을 통해 수행됩니다. 즉, 클라이언트 (브라우저)가 JSON 형식으로 데이터를 전달해야 할 때이 시점에서 문자열이 네트워크에 전달되며 서버 측에는 데이터를 수신 한 후 문자열 (문자열 유형)도 있습니다. 때로는 JSON 문자열을 JSON 객체로 변환 한 다음 다음 작업을 수행해야합니다 (문자열 유형은 JsonObject 유형으로 변환됩니다).
위의 두 개념은 기본적으로 JSON의 데이터 형식을 명확히하거나 JSON 구문이라고도합니다. Java에는 JSON 용 JAN 패키지가 많이 있습니다. 가장 "일반적으로 사용되는"것은 "net.sf.json"이 제공하는 JAR 패키지입니다. 이 기사는이 구덩이 패키지에 중점을 둘 것입니다. 구덩이이지만 광범위한 응용 프로그램이 있습니다. 실제로, Alibaba는 가장 빠른 JSON 패키지, Google의 GSON 및 Jackson이라고 주장하는 Fastjson과 같은 우수한 JSON 패키지가 있습니다. "net.sf.json"패키지를 사용해보십시오. Not only are there any pitfalls, but it is also very old, so old that it cannot download the source code in IDEA. Maven 저장소는 2010 년 버전 2.4에서 중단되었음을 보여줍니다.“net.sf.json”에 대해 이미 알고있는 두 가지 버그 와이 두 버그가 어떻게 생성되었는지에 대해 이야기 해 봅시다.
Java中的JSON坑包――net.sf.json
1. Java 객체가 JSON 객체를 변환하면 GET로 시작하는 모든 메소드가 변환됩니다.
예를 들어 다음 Java 객체를 사용할 수 있다는 의미입니다.
패키지 sfjson; import java.util.list;/*** Kevin이 2017/12/1에 작성했습니다. */public class 학생 {private int id; 개인 목록 <long> courseids; public int getid () {return id; } public void setid (int id) {this.id = id; } public list <Long> getCourseIds () {return courseIds; } public void setcourseIds (list <long> courseIds) {this.courseIds = courseIds; } public string getSql () {//이 클래스에서 SQL 문을 가져 오는 메소드에는 해당 속성 필드 리턴 "SQL입니다"; }}학생 객체를 JSON 객체로 변환 할 때 변환 된 JSON 형식이 다음과 같기를 바랍니다.
{ "id": 1, "courseids": [1, 2, 3]}그러나 JSONOBJECT JSON = JSONOBJECT.FROMOBJECT (학생)의 변환 후 결과; API는 :
다시 말해서, "net.sf.json"은 공개 수정자가 Java 객체를 얻는 것으로 시작하는 메소드를 가져오고 접미사를 JSON 객체의 "키"로 정의하고 해당 키의 "값"으로 시작하는 메소드의 반환 값을 정의 할 수 있습니다. 공개 수정자가 얻는 것으로 시작하고 반환 값을 갖는 방법입니다.
나는 이것이 불합리한 전환 규칙이라고 생각합니다. Java 객체에서 메소드를 정의 하고이 메소드가 "get"로 시작하고 반환 값을 가지고 있기 때문에 노출 되나요? 아니면 클라이언트 (브라우저)로 반환 될 때 프론트 엔드 콘솔 콘솔에 노출됩니까? 저자는이 전환 규칙을 규정합니다. 내가 생각하는 거친 이유는 다음과 같습니다. 공개 방법으로 정의하고 이름을 지정하기 때문에 의도적 으로이 방법을 노출시켜 클라이언트가이를 얻을 권리가 있습니다. 그러나 나는 여전히 이것이 불합리하다고 생각하고 심지어 그것을 버그로 정의합니다. 실제 테스트에 따르면 "net.sf.json"패키지는이 규칙에 따라 변환 될뿐만 아니라 Fastjson과 Jackson 도이 규칙을 따르기 때문에 이러한 방식을 정의하는 것이 합리적이지 않을 수 있습니다. 그러나 Google의 GSON 은이 규칙에 따라 객체를 JSON으로 변환하지 않습니다.
Convert the constructed Student object into a JSON object through JSONObject json = JSONObject.fromObject(student); 학생은 위에서 설명한대로입니다. 이 메소드를 입력 한 후에는 Obbect (Object, JsonConfig)의 과부하 메소드가 계속 호출됩니다. 이 과부하 된 방법에서 인스턴스는 변환 할 객체 객체가 열거, 주석 및 기타 유형인지 여부를 결정하는 데 사용됩니다. 이 특수 유형에는 특별한 판단 방법이 있습니다. 다음은 일반적인 Java Pojo 객체가 있으므로 _fromobject (Object, JsonConfig)로 입력 되며이 방법에 약간의 판단이 있으며 마지막으로 JSON 객체는 DefaultBeanProcessing을 호출하여 생성됩니다. This method is the key, and it will continue to obtain the "property descriptor" through PropertyUtils.getPropertyDescriptors(bean) method. 실제로, 여기에는 속성 디스크립터로 캡슐화 된 Get과 함께 메소드를 얻는 것입니다. 이 학생 수업은 4, 즉 GetClass, GetId, GetCourseIds, GetSql을 얻습니다.
실제로 PropertyDescriptor는 자세히 캡슐화되며 모든 읽기 및 쓰기 방법이 할당되었습니다.
For example, this getSql method has been parsed into the PropertyDescriptor in the figure above. The following is filtered out some methods through this class. 예를 들어, getClass 메소드는 Pojo의 메소드가 아니므로 JSON 객체로 변환 할 필요가 없습니다. PropertyDescriptor는 BeanInfo#getPropertyDescriptors를 통해 얻어지며 BeanInfo는 새로운 introspector (beanclass, null, use_all_beaninfo) .getBeanInfo ()를 통해 얻습니다. 그리고 마침내 다음 방법에 도달하게됩니다.
private beaninfo getBeanInfo ()는 introspectionException {… methodDescriptor mds [] = getTargetMethodinfo (); //이 메소드는 getPublicDeclaredMethods를 호출합니다. 당신은 그것이 실제로 공개 방법을 찾고 있음을 알 수 있으며, 대기 및 기타 PropertyDescriptors pds [] = getTargetPropertyInfo (); // 특정 규칙에 따라 필터. 필터링 규칙은 모두이 방법에 있습니다.이 방법은 공개 수정자가 get 접두사와 반환 값을 갖는 방법을 선택하는 것입니다 ...나는 net.sf.json의 소스 코드를 간단히 분석 한 결과, 특정 소스 코드는 비교적 크고 공간이 제한되어 있으며 직접보고 추적해야한다는 것을 발견했습니다.
2. Java 객체를 JSON 객체로 변환하면 목록에서 변환 오류가 발생합니다.
제목은 한 문장으로 명확하게 설명 할 수 없으며이 문제가 버그라고 확신합니다.
Now there is a JSON string of {"id": 1, "courseIds": [1,2,3]}, and it needs to be converted to the Student object mentioned above. 학생 객체에는 유형 int와 list <long>의 두 속성 필드가 있습니다. 즉,이 JSON 문자열은 해당 데이터 유형으로 변환되어야합니다.
문자열 JSON = "{/"id/": 1,/"courseIds/": [1,2,3]}"; 학생 학생 = (학생) JsonObject.tobean (jsonObject.fromObject (JSON), Student.Class); System.out.println (Student.getCourseIds (). get (0) instancef long);위의 출력은 사실이어야하지만 불행히도 거짓입니다. To be precise, it is Long at compile time, but Integer at run time. This has to be said to be a pitfall, and none of the other three JSON packages have such an error. 그래서 나는 그것이 버그라고 확신합니다. Let’s see how this bug occurs in net.sf.json. 또한 소스 코드를 직접 비교하여이를 볼 필요가 있습니다. 끊임없이 중단 점 디버그를 심화시키는 동안 Net.sf.json이 정수 데이터를 처리 할 때이 메소드 NumberUtils#CreateNumber를 발견했습니다. This class judges its data type when extracting data from a string. 원래 의도는 그 숫자가 "l"또는 "l"가있는 경우 숫자를 오랫동안 처리하는 것입니다. From this point of view, the final result should be correct.
CASE 'l': CASE 'L': if (dec == null && exp == null && (numeric.charat (0) == '-'&& isdigits (numeric.substring (1)) || isdigits (numeric))) {try {return createlong (numeric); } catch (NumberFormatException var11) { return createBigInteger(numeric); }} else {wrach new numberformatexception (str + "는 유효한 숫자가 아닙니다."); }Indeed, so far, net.sf.json has accurately judged the data type through the identifier after the number. 문제는이 값과 데이터 유형을 얻은 후 JsonObject에 저장해야한다는 사실에 있습니다. The method JSONUtils#transformNumber exists during the storage process. The existence of this method is at least purely extravagant in the current view.
공용 정적 번호 변환 번호 (숫자 입력) {if (input instanceof float) {return new double (input.toString ()); } else if (input instanceof Short) { return new Integer(input.intValue()); } else if (input instanceof Byte) { return new Integer(input.intValue()); } else { if (input instanceof Long) { Long max = new Long(2147483647L); if (input.longvalue () <= max.longvalue () && input.longvalue ()> = -2147483648L) {// 정수 범위 내에있는 한 원래 유형이 길어도 결국 정수로 변환됩니다. 새 정수를 반환합니다 (input.intvalue ()); } } return input; }}위의 코드는 바이트 및 짧은 것을 포함하여 긴 유형 (정수 범위 내의 긴 유형)인지 여부에 관계없이 범인을 명확하게 보여 주면 정수로 변환됩니다. I don't understand what the meaning of this code is. 정확한 데이터 유형은 숫자 이후의 문자에 따라 결정되어야하며 정확한 데이터 유형은 나중에 다시 변환되어야하므로 처음에 언급 된 버그로 연결됩니다. This problem is almost unavoidable, so the best way is not to use it.
이 두 가지 함정은 우연히 발견되었습니다. It is recommended not to use the JSON package of net.sf.json that has not been maintained. In addition, the net.sf.json package is not so strict in the verification of JSON format. 그러한 형식이 "{"id ": 1,"courseids ":"[1,2,3] "}"인 경우 다른 세 패키지에서 예외가 발생하지만 Net.sf.json은 그렇지 않습니다.
위의 기사는 JSON의 함정과 Java의 객체 전송에 대해 자세히 설명합니다. 이것은 내가 당신과 공유하는 모든 콘텐츠입니다. 나는 그것이 당신에게 참조를 줄 수 있기를 바랍니다. 그리고 당신이 wulin.com을 더 지원할 수 있기를 바랍니다.