読者です 読者をやめる 読者になる 読者になる

ウェブサービスを作っています。

appengine-apis の memcache.rb を読み込むと Datastore に格納する日本語が文字化けする

appengine-apis のバージョンは 0.0.6 です。
正確には、memcache.rb が内部で読み込んでいる datastore_types.rb のせいです。
Bumble や DataMapper を使っても文字化けしました。


Java は詳しくないのでよくわかりませんが、String#to_java_string が Latin-1 に変換してしまうのが原因のようです。
[#JRUBY-3796] ruby_string.to_java_string has different encoding than new java.lang.String(ruby_string) - jira.codehaus.org


ということで String#to_java_string を java.lang.String.new で書き直したところ直りました。
to_java_string はあちこちで使われているのですが、とりあえず datastore_types.rb の Datastore::ruby_to_java を直せば直ります。

def Datastore.ruby_to_java(value)  # :nodoc:
  if SPECIAL_RUBY_TYPES.include? value.class
    value.to_java
  else
    case value
    when Fixnum
      java.lang.Long.new(value)
    when Float
      java.lang.Double.new(value)
    when String
      #value.to_java_string        # <-- comment out
      java.lang.String.new(value)  # <-- add
    else
      value
    end
  end
end


あと AppEngine::Memcache を String value で実際に使う場合は memcache.rb の AppEngine::Memcache#memcache_value で使われている to_java_string も書き換える必要があります。

def memcache_value(obj)
  case obj
  when Fixnum
    java.lang.Long.new(obj)
  when Float
    java.lang.Double.new(obj)
  when TrueClass, FalseClass
    java.lang.Boolean.new(obj)
  when JavaProxy, Java::JavaObject
    obj
  else
    if obj.class == String
      # Convert plain strings to Java strings
      #obj.to_java_string        # <-- comment out
      java.lang.String.new(obj)  # <-- add
    else
      bytes = Marshal.dump(obj).to_java_bytes
      java.util.ArrayList.new([MARSHAL_MARKER.to_java_string, bytes])
    end
  end
end