Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[serialization]Abstract JSON serialization and use gson as default #1739

Open
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

jasonjoo2010
Copy link
Collaborator

Describe what this PR does / why we need it

Though sentinel-core doesn't need json serialization, but in most sentinel modules (adaption, datasource, etc.) they use fastjson for serializing/deserializing json strings.

Unfortunately there are more and more versions of fastjson which were found vulnerable and users must follow the latest patches or versions. If not their application may become weak and easy to attack.

In the other hand JSON serializing is a common need. So most projects have their own way to do that. In this scene it's not necessary to introduce a new one if sentinel can use existing, compatible serializing library in project.

This PR will enable user letting sentinel to use gson / fastjson / jackson or their own implementation through SPI protocol.

Does this pull request fix one issue?

#1522

Describe how you did it

Introduce a new module sentinel-serialization and take gson as default json serializing/deserializing library.

  • Add new SPI interface JsonSerializer and JsonDeserializer
  • The default implementation adapts to gson and fastjson (gson prior)
  • gson can be excluded manually from dependency tree if use custom implementation
  • Add a popular implementation sentinel-serialization-jackson

Describe how to verify it

Depends.

Special notes for reviews

A wide regressing test may be necessary.

@jasonjoo2010 jasonjoo2010 added the dependencies Pull requests that update a dependency file label Sep 16, 2020
…fault json serializing/deserializing library.

- Add new SPI interface `JsonSerializer` and `JsonDeserializer`
- The default implementation adapts to `gson` and `fastjson` (gson prior)
- `gson` can be excluded manually from dependency tree if use custom implementation
- Add a popular implementation `sentinel-serialization-jackson`

Signed-off-by: Jason Joo <[email protected]>
…ds) in gson

- Update sentinel-demo-cluster-server-alone to demonstrate an example using fastjson in serialization
@sczyh30 sczyh30 requested review from linlinisme, cdfive and a team September 17, 2020 13:18
@jasonjoo2010 jasonjoo2010 changed the title [serialization]Abstract JSON serialization and default to use gson [serialization]Abstract JSON serialization and use gson as default Sep 18, 2020
@sczyh30 sczyh30 added kind/refactor Issue related to functional refactoring. size/XXL Indicate a PR that changes 1000+ lines. to-review To review labels Sep 19, 2020
@zhengpengGitHub
Copy link

hello,when does this fix will release?

Comment on lines +50 to +72
@Override
public String serialize(Object obj) {
if (obj == null) {
return "null";
}
try {
return this.adaption.serialize(obj);
} catch (Exception e) {
}
return null;
}

@Override
public <T> T deserialize(String str, Type type) {
if (StringUtil.isBlank(str)) {
return null;
}
try {
return this.adaption.deserialize(str, type);
} catch (Exception e) {
}
return null;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When serialize and deserialize the exception is ignored, do we need to throw an exception to remind the user to know or record the error log? The same is in JacksonTransformer class.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here just keep the dealing strategy for backward compatibility. (null when failed in most scenarios)
So some logs are needed or a runtime exception should be introduced?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest both throw runtime exception and record error log. Although the exception will be occur in rare case, maybe never, but since we catch the Exception, why not do nothing. If exception occurred, user may want to know what happened. If it's sure that we don't need to deal with it here, suggest adding some comments.

Copy link
Collaborator

@cdfive cdfive Jan 30, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If throw runtime exception, it will affect some test cases.Or just record log? I feel acceptable to ignore the exception,just a thought of it for reference, it's up to you.

Comment on lines +72 to +80
public String serialize(Object obj) throws Exception {
return (String)METHOD_TO_JSON_STRING.invoke(CLASS, obj);
}

@SuppressWarnings("unchecked")
@Override
public <T> T deserialize(String str, Type type) throws Exception {
return (T)METHOD_PARSE_OBJECT_BY_TYPE.invoke(CLASS, str, type, null);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Serialization and deserialization methods called by reflection in FastjsonAdaption and GsonAdaption. Another way is that, the fastjson and gson depenency can be with provided scope, and we can use their class and method calls directly. Which way do you think is better? @jasonjoo2010 @sczyh30

Comment on lines +36 to +40
public DefaultTransformer() {
List<Adaption> adaptions = Arrays.asList(
new GsonAdaption(),
new FastjsonAdaption()
);
Copy link
Collaborator

@cdfive cdfive Jan 30, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jackson seems more widely used, Gson as the default first choice may need to be discussed.
sentinel-serialization-jackson is a separate module, why not JasksonAdaption, will it be more convenient to use? Or GsonAdaption, FastjsonAdaption -> sentinel-serialization-gson, sentinel-serialization-fastjson module, it may be a special consideration, but it seems that there are not uniform implementation.

import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

class DateTypeAdapter implements JsonSerializer<Date>, JsonDeserializer<Date> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GsonDateTypeAdapter may be a better name, or add separate package for gson and fastjson fallback.

@brotherlu-xcq
Copy link
Collaborator

Hi, @jasonjoo2010. I have some question about this design.

  • I find that you split deserialize and serialize to two interface. but in our scene,the relationship bewteen deserialize and serialize should be like the front and back of a coin. It maybe better to put them in an interface.
  • serialize type is not only json, I think design of this module shoud cover other serialize type like hession,etc.

@jasonjoo2010
Copy link
Collaborator Author

Hi, @jasonjoo2010. I have some question about this design.

  • I find that you split deserialize and serialize to two interface. but in our scene,the relationship bewteen deserialize and serialize should be like the front and back of a coin. It maybe better to put them in an interface.
  • serialize type is not only json, I think design of this module shoud cover other serialize type like hession,etc.

Hi Lu

First let's skip the first point you mentioned and go over the second point directly.
The purpose of this PR is aiming to decouple the serialising/deserialising on json string against fastjson library because of more and more versions of that have security risks. That's why it focuses on dealing json only.
But if open our minds to other general purpose serialisations it will be too flexible. Which will make things complicated especially the data will be submitted through http transports while hessian/proto/igbinary is binary serialisation. So it's not a RPC case.
So we want to keep json as the standard encoding in transports.

Come back to the first point not in java but in many languages they are two interfaces(eg. golang). You even can only customize one of them instead of both which make more sense. In the other hand you must name it something new if you want to combine them together. So it's not a big deal I think.
Let me use a more detailed example to make it clear. If you use gson but you are not satisfied with the provided implementation because you want all float type to keep up to 2 decimal places. So if you just want to truncate the inputs from outside you only need to implement a new deserialiser.

@sczyh30 sczyh30 requested a review from zhaoyuguang July 5, 2021 12:20
@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
dependencies Pull requests that update a dependency file kind/refactor Issue related to functional refactoring. size/XXL Indicate a PR that changes 1000+ lines. to-review To review
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants