Skip to content

Commit

Permalink
improve JSONSchema
Browse files Browse the repository at this point in the history
  • Loading branch information
wenshao committed Jul 25, 2023
1 parent 4c9d9b4 commit 6b435db
Show file tree
Hide file tree
Showing 13 changed files with 469 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package com.alibaba.fastjson2.benchmark.twitter;

import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.List;

public class Twitter {
public String text;
public Boolean truncated;
@JsonProperty("in_reply_to_user_id")
public String inReplyToUserId;
@JsonProperty("in_reply_to_status_id")
public String inReplyToStatusId;
public Boolean favorited;
public String source;
@JsonProperty("in_reply_to_screen_name")
public String inReplyToScreenName;
@JsonProperty("in_reply_to_status_id_str")
public String inReplyToStatusIdStr;
@JsonProperty("id_str")
public String idStr;
public Entities entities;
public String contributors;
public Boolean retweeted;
@JsonProperty("in_reply_to_user_id_str")
public String inReplyToUserIdStr;
public String place;
@JsonProperty("retweet_count")
public Integer retweetCount;
@JsonProperty("created_at")
public String createdAt;

@JsonProperty("retweeted_status")
public RetweetedStatus retweetedStatus;
public User user;
public Long id;
public String coordinates;
public String geo;

public static class UserMention {
public List<Integer> indices;
@JsonProperty("screen_name")
public String screenName;
@JsonProperty("id_str")
public String idStr;
public String name;
public Integer id;
}

public static class Entities {
@JsonProperty("user_mentions")
public List<UserMention> userMentions;
public List urls;
public List hashtags;
}

public static class Hashtag {
public String text;
public List<Integer> indices;
}

public static class User {
public String notifications;
@JsonProperty("profile_use_background_image")
public Boolean profileUseBackgroundImage;
@JsonProperty("statuses_count")
public Integer statusesCount;
@JsonProperty("profile_background_color")
public String profileBackgroundColor;
@JsonProperty("followers_count")
public Integer followersCount;
@JsonProperty("profile_image_url")
public String profileImageUrl;
@JsonProperty("listed_count")
public Integer listedCount;
@JsonProperty("profile_background_image_url")
public String profileBackgroundImageUrl;
public String description;
@JsonProperty("screen_name")
public String screenName;
@JsonProperty("default_profile")
public Boolean defaultProfile;
public Boolean verified;
@JsonProperty("time_zone")
public String timeZone;
@JsonProperty("profile_text_color")
public String profileTextColor;
@JsonProperty("is_translator")
public Boolean isTranslator;
@JsonProperty("profile_sidebar_fill_color")
public String profileSidebarFillColor;
public String location;
@JsonProperty("id_str")
public String idStr;
@JsonProperty("default_profile_image")
public Boolean defaultProfileImage;
@JsonProperty("profile_background_tile")
public Boolean profileBackgroundTile;
public String lang;
@JsonProperty("friends_count")
public Integer friendsCount;
@JsonProperty("protected")
public Boolean isProtected;
@JsonProperty("favourites_count")
public Integer favouritesCount;
@JsonProperty("created_at")
public String createdAt;
@JsonProperty("profile_link_color")
public String profileLinkColor;
public String name;
@JsonProperty("show_all_inline_media")
public Boolean showAllInlineMedia;
@JsonProperty("follow_request_sent")
public String followRequestSent;
@JsonProperty("geo_enabled")
public Boolean geoEnabled;
@JsonProperty("profile_sidebar_border_color")
public String profileSidebarBorderColor;
public String url;
public Integer id;
@JsonProperty("contributors_enabled")
public Boolean contributorsEnabled;
public String following;
@JsonProperty("utc_offset")
public String utcOffset;
}

public static class RetweetedStatus {
public String text;
public Boolean truncated;
@JsonProperty("in_reply_to_user_id")
public String inReplyToUserId;
@JsonProperty("in_reply_to_status_id")
public String inReplyToStatusId;
public Boolean favorited;
public String source;
@JsonProperty("in_reply_to_screen_name")
public String inReplyToScreenName;
@JsonProperty("in_reply_to_status_id_str")
public String inReplyToStatusIdStr;
@JsonProperty("id_str")
public String idStr;
public Entities entities;
public String contributors;
public Boolean retweeted;
@JsonProperty("in_reply_to_user_id_str")
public String inReplyToUserIdStr;
public String place;
@JsonProperty("retweet_count")
public Integer retweetCount;
@JsonProperty("created_at")
public String createdAt;
public User user;
public Long id;
public String coordinates;
public String geo;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.alibaba.fastjson2.benchmark.twitter;

import com.alibaba.fastjson2.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import org.apache.commons.io.IOUtils;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import java.io.InputStream;
import java.util.concurrent.TimeUnit;

public class TwitterParseString {
static String str;
static final ObjectMapper mapper = new ObjectMapper();
static final Gson gson = new Gson();

static {
try {
InputStream is = TwitterParseString.class.getClassLoader().getResourceAsStream("data/twitter.json");
str = IOUtils.toString(is, "UTF-8");
JSON.parseObject(str, Twitter.class);
} catch (Throwable ex) {
ex.printStackTrace();
}
}

@Benchmark
public void fastjson2(Blackhole bh) {
bh.consume(JSON.parseObject(str, Twitter.class));
}

@Benchmark
public void jackson(Blackhole bh) throws Exception {
bh.consume(mapper.readValue(str, Twitter.class));
}

public static void main(String[] args) throws RunnerException {
Options options = new OptionsBuilder()
.include(TwitterParseString.class.getName())
.mode(Mode.Throughput)
.timeUnit(TimeUnit.MILLISECONDS)
.warmupIterations(3)
.forks(1)
.threads(16)
.build();
new Runner(options).run();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.alibaba.fastjson2.benchmark.twitter;

import static com.alibaba.fastjson2.benchmark.JMH.BH;

public class TwitterParseStringTest {
static final int LOOP = 1_000_000;
static final TwitterParseString benchmark = new TwitterParseString();

public static void fastjson2() {
for (int j = 0; j < 5; j++) {
long start = System.currentTimeMillis();
for (int i = 0; i < LOOP; ++i) {
benchmark.fastjson2(BH);
}
long millis = System.currentTimeMillis() - start;
System.out.println("fastjson2 millis : " + millis);
// zulu8.70.0.23 : 4128
// zulu11.64.19 :
// zulu17.42.19 :
}
}

public static void jackson() throws Exception {
for (int j = 0; j < 5; j++) {
long start = System.currentTimeMillis();
for (int i = 0; i < LOOP; ++i) {
benchmark.jackson(BH);
}
long millis = System.currentTimeMillis() - start;
System.out.println("jackson millis : " + millis);
// zulu8.70.0.23 : 7605
// zulu11.52.13 :
// zulu17.32.13 :
}
}

public static void main(String[] args) throws Exception {
// fastjson2();
jackson();
// fastjson1();
// gson();
// wastjson();
}
}
13 changes: 13 additions & 0 deletions core/src/main/java/com/alibaba/fastjson2/schema/ArraySchema.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Predicate;

public final class ArraySchema
extends JSONSchema {
Expand Down Expand Up @@ -497,4 +498,16 @@ public JSONObject toJSONObject() {
}
return object;
}

public void accept(Predicate<JSONSchema> v) {
if (v.test(this)) {
if (itemSchema != null) {
itemSchema.accept(v);
}
}
}

public JSONSchema getItemSchema() {
return itemSchema;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import com.alibaba.fastjson2.JSONObject;

final class BooleanSchema
public final class BooleanSchema
extends JSONSchema {
BooleanSchema(JSONObject input) {
super(input);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import static com.alibaba.fastjson2.util.TypeUtils.*;

final class EnumSchema
public final class EnumSchema
extends JSONSchema {
final Set<Object> items;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import static com.alibaba.fastjson2.util.TypeUtils.*;

final class IntegerSchema
public final class IntegerSchema
extends JSONSchema {
final boolean typed;
final long minimum;
Expand Down
54 changes: 51 additions & 3 deletions core/src/main/java/com/alibaba/fastjson2/schema/JSONSchema.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
import java.util.function.Predicate;

@JSONType(serializer = JSONSchema.JSONSchemaWriter.class)
public abstract class JSONSchema {
Expand Down Expand Up @@ -130,7 +131,7 @@ static Not ofNot(JSONObject input, Class objectClass) {
JSONObject object = (JSONObject) not;

if (object == null || object.isEmpty()) {
return new Not(null, new Type[] {Type.Any}, null);
return new Not(null, new Type[]{Type.Any}, null);
}

if (object.size() == 1) {
Expand Down Expand Up @@ -183,16 +184,59 @@ static JSONSchema ofValue(Object value, JSONSchema root) {
return null;
}

if (value instanceof Collection) {
Collection collection = (Collection) value;
if (collection.isEmpty()) {
return new ArraySchema(JSONObject.of("type", "array"), root);
}

Object firstItem = null;
Class firstItemClass = null;
boolean sameClass = true;
for (Object item : collection) {
if (item != null) {
if (firstItem == null) {
firstItem = item;
}

if (firstItemClass == null) {
firstItemClass = item.getClass();
} else if (firstItemClass != item.getClass()) {
sameClass = false;
}
}
}

if (sameClass) {
JSONSchema itemSchema;
if (Map.class.isAssignableFrom(firstItemClass)) {
itemSchema = ofValue(firstItem, root);
} else {
itemSchema = of(firstItemClass, root);
}
ArraySchema schema = new ArraySchema(JSONObject.of("type", "array"), root);
schema.itemSchema = itemSchema;
return schema;
}
}

if (value instanceof Map) {
JSONObject object = JSONObject.of("type", "object");
ObjectSchema schema = new ObjectSchema(object, root);

Map map = (Map) value;
for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
for (Iterator it = map.entrySet().iterator(); it.hasNext(); ) {
Map.Entry entry = (Map.Entry) it.next();
Object entryKey = entry.getKey();
Object entryValue = entry.getValue();

if (entryKey instanceof String) {
JSONSchema valueSchema = ofValue(entry.getValue(), root == null ? schema : root);
JSONSchema valueSchema;
if (entryValue == null) {
valueSchema = new StringSchema(JSONObject.of());
} else {
valueSchema = ofValue(entryValue, root == null ? schema : root);
}
schema.properties.put((String) entryKey, valueSchema);
}
}
Expand Down Expand Up @@ -882,4 +926,8 @@ public void write(JSONWriter jsonWriter,
jsonWriter.write(jsonObject);
}
}

public void accept(Predicate<JSONSchema> v) {
v.test(this);
}
}
Loading

0 comments on commit 6b435db

Please sign in to comment.