Commit 0258ba60 authored by Robert May's avatar Robert May

Revert "Merge branch 'gitlab-json-multi' into 'master'"

This reverts merge request !35527
parent d6f7cbd1
...@@ -500,5 +500,3 @@ gem 'valid_email', '~> 0.1' ...@@ -500,5 +500,3 @@ gem 'valid_email', '~> 0.1'
# JSON # JSON
gem 'json', '~> 2.3.0' gem 'json', '~> 2.3.0'
gem 'json-schema', '~> 2.8.0' gem 'json-schema', '~> 2.8.0'
gem 'oj', '~> 3.10.6'
gem 'multi_json', '~> 1.14.1'
...@@ -687,7 +687,6 @@ GEM ...@@ -687,7 +687,6 @@ GEM
octokit (4.15.0) octokit (4.15.0)
faraday (>= 0.9) faraday (>= 0.9)
sawyer (~> 0.8.0, >= 0.5.3) sawyer (~> 0.8.0, >= 0.5.3)
oj (3.10.6)
omniauth (1.9.0) omniauth (1.9.0)
hashie (>= 3.4.6, < 3.7.0) hashie (>= 3.4.6, < 3.7.0)
rack (>= 1.6.2, < 3) rack (>= 1.6.2, < 3)
...@@ -1313,7 +1312,6 @@ DEPENDENCIES ...@@ -1313,7 +1312,6 @@ DEPENDENCIES
mimemagic (~> 0.3.2) mimemagic (~> 0.3.2)
mini_magick mini_magick
minitest (~> 5.11.0) minitest (~> 5.11.0)
multi_json (~> 1.14.1)
nakayoshi_fork (~> 0.0.4) nakayoshi_fork (~> 0.0.4)
net-ldap net-ldap
net-ntp net-ntp
...@@ -1321,7 +1319,6 @@ DEPENDENCIES ...@@ -1321,7 +1319,6 @@ DEPENDENCIES
nokogiri (~> 1.10.9) nokogiri (~> 1.10.9)
oauth2 (~> 1.4) oauth2 (~> 1.4)
octokit (~> 4.15) octokit (~> 4.15)
oj (~> 3.10.6)
omniauth (~> 1.8) omniauth (~> 1.8)
omniauth-auth0 (~> 2.0.0) omniauth-auth0 (~> 2.0.0)
omniauth-authentiq (~> 0.3.3) omniauth-authentiq (~> 0.3.3)
......
---
title: Add oj gem for faster JSON
merge_request: 35527
author:
type: performance
# frozen_string_literal: true
# Explicitly set the JSON adapter used by MultiJson
# Currently we want this to default to the existing json gem
MultiJson.use(:json_gem)
# frozen_string_literal: true
# Ensure Oj runs in json-gem compatibility mode by default
Oj.default_options = { mode: :rails }
# frozen_string_literal: true # frozen_string_literal: true
# This is a GitLab-specific JSON interface. You should use this instead
# of using `JSON` directly. This allows us to swap the adapter and handle
# legacy issues.
module Gitlab module Gitlab
module Json module Json
INVALID_LEGACY_TYPES = [String, TrueClass, FalseClass].freeze INVALID_LEGACY_TYPES = [String, TrueClass, FalseClass].freeze
class << self class << self
# Parse a string and convert it to a Ruby object def parse(string, *args, **named_args)
# legacy_mode = legacy_mode_enabled?(named_args.delete(:legacy_mode))
# @param string [String] the JSON string to convert to Ruby objects data = adapter.parse(string, *args, **named_args)
# @param opts [Hash] an options hash in the standard JSON gem format
# @return [Boolean, String, Array, Hash]
# @raise [JSON::ParserError] raised if parsing fails
def parse(string, opts = {})
# First we should ensure this really is a string, not some other
# type which purports to be a string. This handles some legacy
# usage of the JSON class.
string = string.to_s unless string.is_a?(String)
legacy_mode = legacy_mode_enabled?(opts.delete(:legacy_mode))
data = adapter_load(string, opts)
handle_legacy_mode!(data) if legacy_mode handle_legacy_mode!(data) if legacy_mode
data data
end end
alias_method :parse!, :parse def parse!(string, *args, **named_args)
legacy_mode = legacy_mode_enabled?(named_args.delete(:legacy_mode))
data = adapter.parse!(string, *args, **named_args)
handle_legacy_mode!(data) if legacy_mode
data
end
# Take a Ruby object and convert it to a string def dump(*args)
# adapter.dump(*args)
# @param object [Boolean, String, Array, Hash, Object] depending on the adapter this can be a variety of types
# @param opts [Hash] an options hash in the standard JSON gem format
# @return [String]
def dump(object, opts = {})
adapter_dump(object, opts)
end end
# Legacy method used in our codebase that might just be an alias for `parse`.
# Will be updated to use our `parse` method.
def generate(*args) def generate(*args)
::JSON.generate(*args) adapter.generate(*args)
end end
# Generates a JSON string and formats it nicely.
# Varies depending on adapter and will be updated to use our methods.
def pretty_generate(*args) def pretty_generate(*args)
::JSON.pretty_generate(*args) adapter.pretty_generate(*args)
end end
private private
# Convert JSON string into Ruby through toggleable adapters. def adapter
# ::JSON
# Must rescue adapter-specific errors and return `parser_error`, and
# must also standardize the options hash to support each adapter as
# they all take different options.
#
# @param string [String] the JSON string to convert to Ruby objects
# @param opts [Hash] an options hash in the standard JSON gem format
# @return [Boolean, String, Array, Hash]
# @raise [JSON::ParserError]
def adapter_load(string, opts = {})
opts = standardize_opts(opts)
if enable_oj?
Oj.load(string, opts)
else
::JSON.parse(string, opts)
end
rescue Oj::ParseError, Encoding::UndefinedConversionError => ex
raise parser_error.new(ex)
end end
# Convert Ruby object to JSON string through toggleable adapters.
#
# @param object [Boolean, String, Array, Hash, Object] depending on the adapter this can be a variety of types
# @param opts [Hash] an options hash in the standard JSON gem format
# @return [String]
def adapter_dump(thing, opts = {})
opts = standardize_opts(opts)
if enable_oj?
Oj.dump(thing, opts)
else
::JSON.dump(thing, opts)
end
end
# Take a JSON standard options hash and standardize it to work across adapters
# An example of this is Oj taking :symbol_keys instead of :symbolize_names
#
# @param opts [Hash]
# @return [Hash]
def standardize_opts(opts = {})
if enable_oj?
opts[:mode] = :rails
opts[:symbol_keys] = opts[:symbolize_keys] || opts[:symbolize_names]
end
opts
end
# The standard parser error we should be returning. Defined in a method
# so we can potentially override it later.
#
# @return [JSON::ParserError]
def parser_error def parser_error
::JSON::ParserError ::JSON::ParserError
end end
# @param [Nil, Boolean] an extracted :legacy_mode key from the opts hash
# @return [Boolean]
def legacy_mode_enabled?(arg_value) def legacy_mode_enabled?(arg_value)
arg_value.nil? ? false : arg_value arg_value.nil? ? false : arg_value
end end
# If legacy mode is enabled, we need to raise an error depending on the values
# provided in the string. This will be deprecated.
#
# @param data [Boolean, String, Array, Hash, Object]
# @return [Boolean, String, Array, Hash, Object]
# @raise [JSON::ParserError]
def handle_legacy_mode!(data) def handle_legacy_mode!(data)
return data unless Feature.enabled?(:json_wrapper_legacy_mode, default_enabled: true) return data unless Feature.enabled?(:json_wrapper_legacy_mode, default_enabled: true)
raise parser_error if INVALID_LEGACY_TYPES.any? { |type| data.is_a?(type) } raise parser_error if INVALID_LEGACY_TYPES.any? { |type| data.is_a?(type) }
end end
# @return [Boolean]
def enable_oj?
Feature.enabled?(:oj_json, default_enabled: true)
end
end end
end end
end end
...@@ -19,7 +19,7 @@ module Gitlab ...@@ -19,7 +19,7 @@ module Gitlab
data.merge!(message) data.merge!(message)
end end
Gitlab::Json.dump(data) + "\n" data.to_json + "\n"
end end
end end
end end
# frozen_string_literal: true # frozen_string_literal: true
require 'spec_helper' require 'fast_spec_helper'
RSpec.describe Gitlab::Ci::Parsers::Accessibility::Pa11y do RSpec.describe Gitlab::Ci::Parsers::Accessibility::Pa11y do
describe '#parse!' do describe '#parse!' do
...@@ -108,7 +108,7 @@ RSpec.describe Gitlab::Ci::Parsers::Accessibility::Pa11y do ...@@ -108,7 +108,7 @@ RSpec.describe Gitlab::Ci::Parsers::Accessibility::Pa11y do
it "sets error_message" do it "sets error_message" do
expect { subject }.not_to raise_error expect { subject }.not_to raise_error
expect(accessibility_report.error_message).to include('JSON parsing failed') expect(accessibility_report.error_message).to include('Pa11y parsing failed')
expect(accessibility_report.errors_count).to eq(0) expect(accessibility_report.errors_count).to eq(0)
expect(accessibility_report.passes_count).to eq(0) expect(accessibility_report.passes_count).to eq(0)
expect(accessibility_report.scans_count).to eq(0) expect(accessibility_report.scans_count).to eq(0)
......
...@@ -30,7 +30,7 @@ RSpec.describe Gitlab::PhabricatorImport::Conduit::Response do ...@@ -30,7 +30,7 @@ RSpec.describe Gitlab::PhabricatorImport::Conduit::Response do
body: 'This is no JSON') body: 'This is no JSON')
expect { described_class.parse!(fake_response) } expect { described_class.parse!(fake_response) }
.to raise_error(Gitlab::PhabricatorImport::Conduit::ResponseError, /unexpected character/) .to raise_error(Gitlab::PhabricatorImport::Conduit::ResponseError, /unexpected token at/)
end end
it 'returns a parsed response for valid input' do it 'returns a parsed response for valid input' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment