Skip to content

Commit

Permalink
Migrate from GSON to our own serializer/deserializer
Browse files Browse the repository at this point in the history
There's a problem where GSON will merrily decode a
number as a double. While technically correct, this
causes Bad Things to happen with interop. Fortunatley
our own JSON <-> Bean converters Do The Right Thing
already. Switch to using those.
  • Loading branch information
shs96c committed Aug 21, 2017
1 parent f9aa0e2 commit d4eb9a2
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 50 deletions.
17 changes: 11 additions & 6 deletions java/server/src/org/openqa/selenium/remote/server/AllHandlers.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import org.openqa.selenium.remote.BeanToJsonConverter;
import org.openqa.selenium.remote.JsonToBeanConverter;
import org.openqa.selenium.remote.SessionId;
import org.openqa.selenium.remote.http.HttpMethod;
import org.openqa.selenium.remote.server.commandhandler.GetAllSessions;
Expand All @@ -51,12 +51,16 @@

class AllHandlers {

private final static Gson GSON = new GsonBuilder().setLenient().serializeNulls().create();
private final JsonToBeanConverter toBean;
private final BeanToJsonConverter toJson;
private final ActiveSessions allSessions;

private final Map<HttpMethod, ImmutableList<Function<String, CommandHandler>>> additionalHandlers;

public AllHandlers(ActiveSessions allSessions) {
this.toBean = new JsonToBeanConverter();
this.toJson = new BeanToJsonConverter();

this.allSessions = allSessions;

additionalHandlers = ImmutableMap.of(
Expand Down Expand Up @@ -99,12 +103,12 @@ public CommandHandler match(HttpServletRequest req) {
if (id != null) {
ActiveSession session = allSessions.get(id);
if (session == null) {
return new NoSessionHandler(id);
return new NoSessionHandler(toJson, id);
}
return session;
}

return new NoHandler();
return new NoHandler(toJson);
}

private <H extends CommandHandler> Function<String, CommandHandler> handler(
Expand All @@ -119,7 +123,8 @@ private <H extends CommandHandler> Function<String, CommandHandler> handler(

ImmutableSet.Builder<Object> args = ImmutableSet.builder();
args.add(allSessions);
args.add(GSON);
args.add(toBean);
args.add(toJson);
if (match.getParameters().containsKey("sessionId")) {
SessionId id = new SessionId(match.getParameters().get("sessionId"));
args.add(id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
import static org.openqa.selenium.remote.ErrorCodes.SUCCESS;

import com.google.common.collect.ImmutableMap;
import com.google.gson.GsonBuilder;

import org.openqa.selenium.remote.BeanToJsonConverter;
import org.openqa.selenium.remote.http.HttpRequest;
import org.openqa.selenium.remote.http.HttpResponse;
import org.openqa.selenium.remote.server.ActiveSessions;
Expand All @@ -34,13 +34,16 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

public class GetAllSessions implements CommandHandler {

private volatile ActiveSessions allSessions;
private final ActiveSessions allSessions;
private final BeanToJsonConverter toJson;

public GetAllSessions(ActiveSessions allSessions) {
this.allSessions = allSessions;
public GetAllSessions(ActiveSessions allSessions, BeanToJsonConverter toJson) {
this.allSessions = Objects.requireNonNull(allSessions);
this.toJson = Objects.requireNonNull(toJson);
}

@Override
Expand All @@ -55,10 +58,7 @@ public void execute(HttpRequest req, HttpResponse resp) throws IOException {
"value", value);

// Write out a minimal W3C status response.
byte[] payload = new GsonBuilder()
.serializeNulls()
.create()
.toJson(payloadObj).getBytes(UTF_8);
byte[] payload = toJson.convert(payloadObj).getBytes(UTF_8);

resp.setStatus(HTTP_OK);
resp.setHeader("Content-Type", JSON_UTF_8.toString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,28 @@
import static org.openqa.selenium.remote.http.HttpMethod.GET;

import com.google.common.collect.ImmutableSet;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import org.openqa.selenium.logging.LogType;
import org.openqa.selenium.remote.ErrorCodes;
import org.openqa.selenium.remote.JsonToBeanConverter;
import org.openqa.selenium.remote.Response;
import org.openqa.selenium.remote.http.HttpRequest;
import org.openqa.selenium.remote.http.HttpResponse;
import org.openqa.selenium.remote.server.ActiveSession;
import org.openqa.selenium.remote.server.CommandHandler;

import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;

public class GetLogTypes implements CommandHandler {

private static final Type MAP_TYPE = new TypeToken<Map<String, Object>>(){}.getType();
private final Gson gson;
private final JsonToBeanConverter toBean;
private final ActiveSession session;

public GetLogTypes(Gson gson, ActiveSession session) {
this.gson = Objects.requireNonNull(gson);
public GetLogTypes(JsonToBeanConverter toBean, ActiveSession session) {
this.toBean = Objects.requireNonNull(toBean);
this.session = Objects.requireNonNull(session);
}

Expand All @@ -60,7 +57,7 @@ public void execute(HttpRequest req, HttpResponse resp) throws IOException {
types.add(LogType.SERVER);

if (upRes.getStatus() == HTTP_OK) {
Map<String, Object> upstream = gson.fromJson(upRes.getContentString(), MAP_TYPE);
Map<?, ?> upstream = toBean.convert(Map.class, upRes.getContentString());
Object raw = upstream.get("value");
if (raw instanceof Collection) {
((Collection<?>) raw).stream().map(String::valueOf).forEach(types::add);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,10 @@
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.openqa.selenium.remote.http.HttpMethod.POST;

import com.google.gson.Gson;

import org.openqa.selenium.logging.LogEntries;
import org.openqa.selenium.logging.LogType;
import org.openqa.selenium.remote.ErrorCodes;
import org.openqa.selenium.remote.JsonToBeanConverter;
import org.openqa.selenium.remote.Response;
import org.openqa.selenium.remote.http.HttpRequest;
import org.openqa.selenium.remote.http.HttpResponse;
Expand All @@ -34,22 +33,23 @@

import java.io.IOException;
import java.util.Map;
import java.util.Objects;

public class GetLogsOfType implements CommandHandler {

private final Gson gson;
private final JsonToBeanConverter toBean;
private final ActiveSession session;

public GetLogsOfType(Gson gson, ActiveSession session) {
this.gson = gson;
this.session = session;
public GetLogsOfType(JsonToBeanConverter toBean, ActiveSession session) {
this.toBean = Objects.requireNonNull(toBean);
this.session = Objects.requireNonNull(session);
}

@Override
public void execute(HttpRequest req, HttpResponse resp) throws IOException {
String originalPayload = req.getContentString();

Map<?, ?> args = gson.fromJson(originalPayload, Map.class);
Map<?, ?> args = toBean.convert(Map.class, originalPayload);
String type = (String) args.get("type");

if (!LogType.SERVER.equals(type)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
import static org.openqa.selenium.remote.ErrorCodes.UNKNOWN_COMMAND;

import com.google.common.collect.ImmutableMap;
import com.google.gson.GsonBuilder;

import org.openqa.selenium.remote.BeanToJsonConverter;
import org.openqa.selenium.remote.http.HttpRequest;
import org.openqa.selenium.remote.http.HttpResponse;
import org.openqa.selenium.remote.server.CommandHandler;
Expand All @@ -33,9 +33,16 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

public class NoHandler implements CommandHandler {

private final BeanToJsonConverter toJson;

public NoHandler(BeanToJsonConverter toJson) {
this.toJson = Objects.requireNonNull(toJson);
}

@Override
public void execute(HttpRequest req, HttpResponse resp) throws IOException {
// We're not using ImmutableMap for the outer map because it disallows null values.
Expand All @@ -51,8 +58,7 @@ public void execute(HttpRequest req, HttpResponse resp) throws IOException {
"stacktrace", ""));
responseMap = Collections.unmodifiableMap(responseMap);

byte[] payload = new GsonBuilder().serializeNulls().create().toJson(responseMap)
.getBytes(UTF_8);
byte[] payload = toJson.convert(responseMap).getBytes(UTF_8);

resp.setStatus(HTTP_NOT_FOUND);
resp.setHeader("Content-Type", JSON_UTF_8.toString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
import static org.openqa.selenium.remote.ErrorCodes.NO_SUCH_SESSION;

import com.google.common.collect.ImmutableMap;
import com.google.gson.GsonBuilder;

import org.openqa.selenium.remote.BeanToJsonConverter;
import org.openqa.selenium.remote.SessionId;
import org.openqa.selenium.remote.http.HttpRequest;
import org.openqa.selenium.remote.http.HttpResponse;
Expand All @@ -34,13 +34,16 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

public class NoSessionHandler implements CommandHandler {

private final BeanToJsonConverter toJson;
private final SessionId sessionId;

public NoSessionHandler(SessionId sessionId) {
this.sessionId = sessionId;
public NoSessionHandler(BeanToJsonConverter toJson, SessionId sessionId) {
this.toJson = Objects.requireNonNull(toJson);
this.sessionId = Objects.requireNonNull(sessionId);
}

@Override
Expand All @@ -55,8 +58,7 @@ public void execute(HttpRequest req, HttpResponse resp) throws IOException {
"stacktrace", ""));
responseMap = Collections.unmodifiableMap(responseMap);

byte[] payload = new GsonBuilder().serializeNulls().create().toJson(responseMap)
.getBytes(UTF_8);
byte[] payload = toJson.convert(responseMap).getBytes(UTF_8);

resp.setStatus(HTTP_NOT_FOUND);
resp.setHeader("Content-Type", JSON_UTF_8.toString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,25 @@
import static org.openqa.selenium.remote.ErrorCodes.SUCCESS;

import com.google.common.collect.ImmutableMap;
import com.google.gson.GsonBuilder;

import org.openqa.selenium.internal.BuildInfo;
import org.openqa.selenium.remote.BeanToJsonConverter;
import org.openqa.selenium.remote.http.HttpRequest;
import org.openqa.selenium.remote.http.HttpResponse;
import org.openqa.selenium.remote.server.CommandHandler;

import java.io.IOException;
import java.util.Map;
import java.util.Objects;

public class Status implements CommandHandler {

private final BeanToJsonConverter toJson;

Status(BeanToJsonConverter toJson) {
this.toJson = Objects.requireNonNull(toJson);
}

@Override
public void execute(HttpRequest req, HttpResponse resp) throws IOException {
ImmutableMap.Builder<String, Object> value = ImmutableMap.builder();
Expand Down Expand Up @@ -63,10 +70,7 @@ public void execute(HttpRequest req, HttpResponse resp) throws IOException {
"value", value.build());

// Write out a minimal W3C status response.
byte[] payload = new GsonBuilder()
.serializeNulls()
.create()
.toJson(payloadObj).getBytes(UTF_8);
byte[] payload = toJson.convert(payloadObj).getBytes(UTF_8);

resp.setStatus(HTTP_OK);
resp.setHeader("Content-Type", JSON_UTF_8.toString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,10 @@

package org.openqa.selenium.remote.server.commandhandler;

import com.google.gson.Gson;

import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.io.Zip;
import org.openqa.selenium.remote.ErrorCodes;
import org.openqa.selenium.remote.JsonToBeanConverter;
import org.openqa.selenium.remote.Response;
import org.openqa.selenium.remote.http.HttpRequest;
import org.openqa.selenium.remote.http.HttpResponse;
Expand All @@ -35,17 +34,17 @@

public class UploadFile implements CommandHandler {

private final Gson gson;
private final JsonToBeanConverter toBean;
private final ActiveSession session;

public UploadFile(Gson gson, ActiveSession session) {
this.gson = Objects.requireNonNull(gson);
public UploadFile(JsonToBeanConverter toBean, ActiveSession session) {
this.toBean = Objects.requireNonNull(toBean);
this.session = Objects.requireNonNull(session);
}

@Override
public void execute(HttpRequest req, HttpResponse resp) throws IOException {
Map<?, ?> args = gson.fromJson(req.getContentString(), Map.class);
Map<?, ?> args = toBean.convert(Map.class, req.getContentString());
String file = (String) args.get("file");

File tempDir = session.getFileSystem().createTempDir("upload", "file");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public void shouldWriteABase64EncodedZippedFileToDiskAndKeepName() throws Except
String encoded = Zip.zip(tempFile);

Gson gson = new Gson();
UploadFile uploadFile = new UploadFile(gson, session);
UploadFile uploadFile = new UploadFile(new JsonToBeanConverter(), session);
Map<String, Object> args = ImmutableMap.of("file", (Object) encoded);
HttpRequest request = new HttpRequest(HttpMethod.POST, "/session/%d/se/file");
request.setContent(gson.toJson(args).getBytes(UTF_8));
Expand All @@ -106,7 +106,7 @@ public void shouldThrowAnExceptionIfMoreThanOneFileIsSent() throws Exception {
String encoded = Zip.zip(baseDir);

Gson gson = new Gson();
UploadFile uploadFile = new UploadFile(gson, session);
UploadFile uploadFile = new UploadFile(new JsonToBeanConverter(), session);
Map<String, Object> args = ImmutableMap.of("file", (Object) encoded);
HttpRequest request = new HttpRequest(HttpMethod.POST, "/session/%d/se/file");
request.setContent(gson.toJson(args).getBytes(UTF_8));
Expand Down

0 comments on commit d4eb9a2

Please sign in to comment.