আমি জ্যাকসন ব্যবহার করে কোনও বস্তুতে কাঁচা জেএসএনকে কীভাবে অন্তর্ভুক্ত করতে পারি?


102

জ্যাকসন ব্যবহার করে যখন বস্তুটি (ডি) সিরিয়ালযুক্ত করা হচ্ছে তখন আমি জাভা অবজেক্টের মধ্যে কাঁচা জেএসএনকে অন্তর্ভুক্ত করার চেষ্টা করছি। এই কার্যকারিতাটি পরীক্ষা করার জন্য, আমি নিম্নলিখিত পরীক্ষাটি লিখেছি:

public static class Pojo {
    public String foo;

    @JsonRawValue
    public String bar;
}

@Test
public void test() throws JsonGenerationException, JsonMappingException, IOException {

    String foo = "one";
    String bar = "{\"A\":false}";

    Pojo pojo = new Pojo();
    pojo.foo = foo;
    pojo.bar = bar;

    String json = "{\"foo\":\"" + foo + "\",\"bar\":" + bar + "}";

    ObjectMapper objectMapper = new ObjectMapper();
    String output = objectMapper.writeValueAsString(pojo);
    System.out.println(output);
    assertEquals(json, output);

    Pojo deserialized = objectMapper.readValue(output, Pojo.class);
    assertEquals(foo, deserialized.foo);
    assertEquals(bar, deserialized.bar);
}

কোড নিম্নলিখিত লাইন আউটপুট:

{"foo":"one","bar":{"A":false}}

JSON হ'ল আমি কীভাবে জিনিসগুলি দেখতে চাই। দুর্ভাগ্যক্রমে, জেএসএনকে আবার অবজেক্টে পড়ার চেষ্টা করার সময় কোডটি একটি ব্যতিক্রম সহ ব্যর্থ হয়। ব্যতিক্রম এখানে:

org.codehaus.jackson.map.JsonMappingException: java.lang.String এর উদাহরণটি deOrialize করতে পারে না [সূত্র: java.io.StringReader@d70d7a এ START_OBJECT টোকেনের বাইরে; লাইন: 1, কলাম: 13] (রেফারেন্স চেইনের মাধ্যমে: com.tnal.prism.cobalt.gather.testing.Pojo ["বার"])

জ্যাকসন কেন এক দিক থেকে ঠিকঠাকভাবে কাজ করে কিন্তু অন্য দিকে যাওয়ার সময় ব্যর্থ হয়? দেখে মনে হচ্ছে এটি আবার ইনপুট হিসাবে নিজস্ব আউটপুট নিতে সক্ষম হবে। আমি জানি যে আমি যা করার চেষ্টা করছি তা অপ্রথাবাদী (সাধারণ পরামর্শ barযার মধ্যে একটি সম্পত্তি নামে একটি অভ্যন্তরীণ বস্তু তৈরি করা হয় A), তবে আমি এই জেএসএনের সাথে কোনওভাবেই যোগাযোগ করতে চাই না। আমার কোডটি এই কোডটির পাস-থ্রো হিসাবে কাজ করছে - আমি এই JSON এ নিয়ে কোনও জিনিস স্পর্শ না করে এটিকে আবার ফেরত পাঠাতে চাই, কারণ যখন JSON পরিবর্তন হয় তখন আমি চাই না যে আমার কোডটিতে পরিবর্তন দরকার।

পরামর্শের জন্য ধন্যবাদ.

সম্পাদনা: পোজোকে একটি স্ট্যাটিক ক্লাস তৈরি করা হয়েছে, যা একটি পৃথক ত্রুটি ঘটছিল।

উত্তর:


64

বিপরীত দিকটি পরিচালনা করতে কিছুটা কৌশলযুক্ত হওয়ায় @ জসনরওভ্যালু কেবল সিরিয়ালাইজেশন-সাইডের জন্যই তৈরি। কার্যকরভাবে এটি প্রাক-এনকোডযুক্ত সামগ্রী ইনজেকশন দেওয়ার জন্য যুক্ত করা হয়েছিল।

আমি অনুমান করি যে বিপরীতে সমর্থন যোগ করা সম্ভব হবে, যদিও এটি বেশ বিশ্রী হবে: সামগ্রীটি বিশ্লেষণ করতে হবে এবং তারপরে আবার "কাঁচা" ফর্মে আবার লিখিত হবে যা একই হতে পারে বা নাও হতে পারে (চরিত্রের উদ্ধৃতি হিসাবে ভিন্ন হতে পারে). এটি সাধারণ ক্ষেত্রে। তবে সম্ভবত এটি কিছু উপসর্গগুলির জন্য অর্থবোধ করবে।

তবে আমি মনে করি আপনার নির্দিষ্ট কেসটির জন্য একটি কাজ 'java.lang.Object' হিসাবে নির্দিষ্ট করা উচিত, যেহেতু এটি ঠিকঠাক কাজ করা উচিত: সিরিয়ালাইজেশনের জন্য স্ট্রিং আউটপুট যেমন হবে তেমনই এবং ডিসিরিয়ালাইজেশনের জন্য এটি ডিসরিয়ালাইজড হবে একটি মানচিত্র. আসলে আপনার আলাদা গেটর / সেটার থাকতে পারে যদি তা হয়; গেটর সিরিয়ালাইজেশনের জন্য স্ট্রিং ফিরে আসবে (এবং @ জসনআরভ্যালু প্রয়োজন); এবং সেটার মানচিত্র বা অবজেক্ট উভয়ই গ্রহণ করবে। আপনি যদি এটি স্ট্রিংতে পুনরায় এনকোড করতে পারেন তা যদি বোঝা যায়।


1
এটি একটি কবজির মতো কাজ করে; কোডের জন্য আমার প্রতিক্রিয়াটি দেখুন ( মন্তব্যে ফর্ম্যাট করা অ্যাগ্রুল )।
yves amsellem

আমি এই জন্য একটি পৃথক ব্যবহারের কেস ছিল। মনে হয় যদি আমরা প্রান / সার্ভারে প্রচুর স্ট্রিং আবর্জনা তৈরি করতে না চাই, তবে আমাদের কেবল একটি স্ট্রিং পাসস্ট্রূথ করতে সক্ষম হওয়া উচিত। আমি এটি দেখতে পেয়েছি এমন একটি থ্রেড দেখেছি, তবে মনে হচ্ছে কোনও দেশীয় সমর্থন সম্ভব নয়। মার্কমেইল.আর
সিড

@ যেভাবে এবং টোকেনাইজেশন উভয়ই দক্ষতার সাথে করার উপায় নেই। অ-প্রক্রিয়াজাত টোকেনগুলির পাস-থ্রো সমর্থন করার জন্য অতিরিক্ত স্টেট-রক্ষণ দরকার যা "নিয়মিত" পার্সিং কিছুটা কম দক্ষ করে তোলে। এটি নিয়মিত কোড এবং ব্যতিক্রম নিক্ষেপের মধ্যে অপ্টিমাইজেশনের মতো: পূর্ববর্তীটির পক্ষে ওভারহেড যুক্ত করে পরে সমর্থন করা। জ্যাকসনকে কোনও প্রসেসড ইনপুট উপলব্ধ রাখার চেষ্টা করার জন্য ডিজাইন করা হয়নি; এটি (ত্রুটি বার্তাগুলির জন্যও) খুব কাছাকাছি থাকলে ভাল লাগবে, তবে আলাদা পদ্ধতির প্রয়োজন হবে।
স্ট্যাক্সমান

55

@ স্ট্যাক্সম্যানের উত্তর অনুসরণ করে , আমি নিচের কাজগুলিকে কবজ হিসাবে তৈরি করেছি:

public class Pojo {
  Object json;

  @JsonRawValue
  public String getJson() {
    // default raw value: null or "[]"
    return json == null ? null : json.toString();
  }

  public void setJson(JsonNode node) {
    this.json = node;
  }
}

এবং, প্রাথমিক প্রশ্নের প্রতি বিশ্বস্ত থাকার জন্য, এখানে কার্যকরী পরীক্ষা:

public class PojoTest {
  ObjectMapper mapper = new ObjectMapper();

  @Test
  public void test() throws IOException {
    Pojo pojo = new Pojo("{\"foo\":18}");

    String output = mapper.writeValueAsString(pojo);
    assertThat(output).isEqualTo("{\"json\":{\"foo\":18}}");

    Pojo deserialized = mapper.readValue(output, Pojo.class);
    assertThat(deserialized.json.toString()).isEqualTo("{\"foo\":18}");
    // deserialized.json == {"foo":18}
  }
}

1
আমি চেষ্টা করিনি, তবে এটির কাজ করা উচিত: 1) অবজেক্ট জসন 2 এর পরিবর্তে একটি জসননোড নোড তৈরি করুন) টুস্ট্রিং () এর পরিবর্তে নোড.এএসটেক্সট () ব্যবহার করুন। আমি যদিও ২ য়টির বিষয়ে নিশ্চিত নই।
ভাদিম কিরিলচুক

আমি অবাক হই কেন কেন সব পরে getJson()ফিরে আসে String। যদি এটি কেবল JsonNodeসেটারের মাধ্যমে সেটটি ফিরিয়ে দেয় তবে এটি পছন্দসই হিসাবে সিরিয়াল করা হবে, না?
দুঃখিতমিসিজ্যাকসন

@ ভাদিমকিরিলচুক node.asText()খালি মানের বিপরীতে ফিরে আসে toString()
v.ladynev

36

আমি একটি কাস্টম ডিসরিয়ালাইজার দিয়ে এটি করতে সক্ষম হয়েছি ( এখান থেকে কাটা এবং আটকানো হয়েছে )

package etc;

import java.io.IOException;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;

/**
 * Keeps json value as json, does not try to deserialize it
 * @author roytruelove
 *
 */
public class KeepAsJsonDeserialzier extends JsonDeserializer<String> {

    @Override
    public String deserialize(JsonParser jp, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {

        TreeNode tree = jp.getCodec().readTree(jp);
        return tree.toString();
    }
}

6
আশ্চর্যজনক কত সহজ। আইএমও এটির সরকারী উত্তর হওয়া উচিত। আমি অ্যারে, সাবওবজেক্টস ইত্যাদিসহ একটি খুব জটিল কাঠামো দিয়ে চেষ্টা করেছি সম্ভবত আপনি নিজের উত্তরটি সম্পাদনা করুন এবং যুক্ত করেছেন যে স্ট্রিং সদস্যকে ডিসিরিয়ালাইজড হতে হবে তা @ জসনডিজারালাইজ (= কিপএএসজেসন ডিজাইরিজায়ার.ক্লাস ব্যবহার করে) দ্বারা টীকা দেওয়া উচিত। (এবং আপনার শ্রেণীর নাম ;
Heri

এটি ডিসেরিয়ালাইজিয়নের জন্য কাজ করে। কীভাবে কাঁচা জসনকে পোজোর সিরিয়ালাইজেশন করা যায়? কীভাবে এটি সম্পন্ন হবে
xtrakBandit

4
সিরিয়ালাইজেশনের জন্য @xtrakBandit, ব্যবহার করুন@JsonRawValue
স্মার্টওয়জডাব্লু

এটি একটি কবজির মতো কাজ করে। ধন্যবাদ রায় এবং @ হেরি .. হিরির মন্তব্যের সাথে এই পোস্টের সংমিশ্রণটি হ'ল সেরা উত্তর।
মিশাল

সহজ এবং ঝরঝরে সমাধান। আমি @ হেরির সাথে একমত
মাহেশ নানায়াক্কার

18

@ জেসনসেটর সাহায্য করতে পারে। আমার নমুনা দেখুন ('ডেটা' তে আনসারসড জেএসওএন রয়েছে বলে ধারণা করা হচ্ছে):

class Purchase
{
    String data;

    @JsonProperty("signature")
    String signature;

    @JsonSetter("data")
    void setData(JsonNode data)
    {
        this.data = data.toString();
    }
}

3
জসননোড.টোস্ট্রিং () ডকুমেন্টেশন পদ্ধতি অনুসারে নোডের বিকাশকারী-পঠনযোগ্য প্রতিনিধিত্ব করবে; যা <b> বা না </ b> বৈধ JSON হিসাবে হতে পারে। সুতরাং এটি আসলে খুব ঝুঁকিপূর্ণ বাস্তবায়ন।
পাইওটার

@ পাইওটর জাভাদোক এখন বলেছেন "স্ট্রিং হিসাবে ডেটাবাইন্ডের ডিফল্ট সেটিংস ব্যবহার করে বৈধ জেএসনকে (জ্যাকসন ২.১০ হিসাবে) বৈধ জেএসএন উত্পাদন করার পদ্ধতি"
বার্নি

4

যোগ করা হচ্ছে রায় প্রকৃত প্রেমিক এর মহান উত্তর , কিভাবে এই চেহারা প্রতিক্রিয়ায় কাস্টম deserialiser উদ্বুদ্ধ হয় @JsonRawValue:

import com.fasterxml.jackson.databind.Module;

@Component
public class ModuleImpl extends Module {

    @Override
    public void setupModule(SetupContext context) {
        context.addBeanDeserializerModifier(new BeanDeserializerModifierImpl());
    }
}

import java.util.Iterator;

import com.fasterxml.jackson.annotation.JsonRawValue;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.deser.BeanDeserializerBuilder;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
import com.fasterxml.jackson.databind.deser.SettableBeanProperty;

public class BeanDeserializerModifierImpl extends BeanDeserializerModifier {
    @Override
    public BeanDeserializerBuilder updateBuilder(DeserializationConfig config, BeanDescription beanDesc, BeanDeserializerBuilder builder) {
        Iterator<SettableBeanProperty> it = builder.getProperties();
        while (it.hasNext()) {
            SettableBeanProperty p = it.next();
            if (p.getAnnotation(JsonRawValue.class) != null) {
                builder.addOrReplaceProperty(p.withValueDeserializer(KeepAsJsonDeserialzier.INSTANCE), true);
            }
        }
        return builder;
    }
}

এটি জ্যাকসন ২.৯-তে কাজ করে না। দেখে মনে হচ্ছে এটি ভেঙে গেছে কারণ এখন এটি সম্পত্তি পরিবর্তিত পরিবর্তে প্রপার্টিবেসড্রিয়েটর.কমস্ট্রাক্টে পুরানো সম্পত্তি ব্যবহার করেছে
dant3

3

এটি আপনার অভ্যন্তরীণ ক্লাসগুলির সাথে সমস্যা। Pojoবর্গ একটি হল অ স্ট্যাটিক ভেতরের বর্গ আপনার পরীক্ষার বর্গ, এবং জ্যাকসন না instantiate যে বর্গ পারেন। সুতরাং এটি সিরিয়ালাইজ করতে পারে, তবে ডিজিটালাইজ করা যায় না।

আপনার ক্লাসটিকে নতুনভাবে সংজ্ঞা দিন:

public static class Pojo {
    public String foo;

    @JsonRawValue
    public String bar;
}

সংযোজন নোট করুন static


ধন্যবাদ। এটি আমাকে আরও একধাপ এগিয়ে পেয়েছিল তবে এখন আমি অন্যরকম ত্রুটি পাচ্ছি। আমি নতুন ত্রুটি সহ মূল পোস্টটি আপডেট করব।
ভিলাস্ট্রোম

3

এই সহজ সমাধানটি আমার পক্ষে কাজ করেছে:

public class MyObject {
    private Object rawJsonValue;

    public Object getRawJsonValue() {
        return rawJsonValue;
    }

    public void setRawJsonValue(Object rawJsonValue) {
        this.rawJsonValue = rawJsonValue;
    }
}

সুতরাং আমি কাঁচা জসনভ্যালু ভেরিয়েবলে জেএসওনের কাঁচা মান সংরক্ষণ করতে সক্ষম হয়েছি এবং তারপরে এটি অন্য পণ্যগুলির সাথে জেএসওনে ফেরত পাঠাতে এবং আমার আরএসটি-র মাধ্যমে প্রেরণে কোনও সমস্যা হয়নি। সঞ্চিত জেএসওএনকে স্ট্রিং হিসাবে ডিসরিয়ালাইজড করা হয়েছিল, বস্তু হিসাবে নয়, এবং এটি আমার ইচ্ছা ছিল না বলে @ জসনআরওভ্যালু ব্যবহার করা আমাকে সহায়তা করেনি।


3

এটি এমনকি জেপিএ সত্তায়ও কাজ করে:

private String json;

@JsonRawValue
public String getJson() {
    return json;
}

public void setJson(final String json) {
    this.json = json;
}

@JsonProperty(value = "json")
public void setJsonRaw(JsonNode jsonNode) {
    // this leads to non-standard json, see discussion: 
    // setJson(jsonNode.toString());

    StringWriter stringWriter = new StringWriter();
    ObjectMapper objectMapper = new ObjectMapper();
    JsonGenerator generator = 
      new JsonFactory(objectMapper).createGenerator(stringWriter);
    generator.writeTree(n);
    setJson(stringWriter.toString());
}

আদর্শভাবে অবজেক্টম্যাপার এবং এমনকি জসনফ্যাক্টরি প্রসঙ্গ থেকে আসে এবং আপনার জেএসওএনকে সঠিকভাবে পরিচালনা করতে এমনভাবে কনফিগার করা হয় (উদাহরণস্বরূপ স্ট্যান্ডার্ড বা 'ইনফিনিটি' ভাসমান) non


1
JsonNode.toString()ডকুমেন্টেশন অনুসারে Method that will produce developer-readable representation of the node; which may <b>or may not</b> be as valid JSON.সুতরাং এটি আসলে খুব ঝুঁকিপূর্ণ বাস্তবায়ন।
পাইওটার

হাই @ পাইওটার, ইঙ্গিতটির জন্য ধন্যবাদ আপনি অবশ্যই সঠিক, এটি JsonNode.asText()অভ্যন্তরীণভাবে ব্যবহার করে এবং অনন্ত এবং অন্যান্য অ-মানক JSON মান আউটপুট দেয়।
জর্জি

@ পাইওটর জাভাদোক এখন বলেছেন "স্ট্রিং হিসাবে ডেটাবাইন্ডের ডিফল্ট সেটিংস ব্যবহার করে বৈধ জেএসনকে (জ্যাকসন ২.১০ হিসাবে) বৈধ জেএসএন উত্পাদন করার পদ্ধতি"
বার্নি

2

জ্যাকসন মডিউলগুলি কীভাবে @JsonRawValueউভয় উপায়ে (সিরিয়ালাইজেশন এবং ডিসরিয়ালাইজেশন) করা যায় তার পুরো কার্যকারণ উদাহরণ এখানে :

public class JsonRawValueDeserializerModule extends SimpleModule {

    public JsonRawValueDeserializerModule() {
        setDeserializerModifier(new JsonRawValueDeserializerModifier());
    }

    private static class JsonRawValueDeserializerModifier extends BeanDeserializerModifier {
        @Override
        public BeanDeserializerBuilder updateBuilder(DeserializationConfig config, BeanDescription beanDesc, BeanDeserializerBuilder builder) {
            builder.getProperties().forEachRemaining(property -> {
                if (property.getAnnotation(JsonRawValue.class) != null) {
                    builder.addOrReplaceProperty(property.withValueDeserializer(JsonRawValueDeserializer.INSTANCE), true);
                }
            });
            return builder;
        }
    }

    private static class JsonRawValueDeserializer extends JsonDeserializer<String> {
        private static final JsonDeserializer<String> INSTANCE = new JsonRawValueDeserializer();

        @Override
        public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
            return p.readValueAsTree().toString();
        }
    }
}

তারপরে আপনি মডিউলটি তৈরির পরে নিবন্ধভুক্ত করতে পারেন ObjectMapper:

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JsonRawValueDeserializerModule());

String json = "{\"foo\":\"one\",\"bar\":{\"A\":false}}";
Pojo deserialized = objectMapper.readValue(json, Pojo.class);

উপরোক্ত জিনিসগুলি ছাড়াও আপনার আরও কিছু কি আছে? আমি দেখতে পেয়েছি যে জসনআরওভ্যালুডিজারাইজারের ডিসরিয়ালাইজ পদ্ধতিটি কখনই অবজেক্টম্যাপার দ্বারা কল হয় না
মাইকেল কক্সন

@ মিশেলকক্সন আপনি কি এটি কাজ করতে পরিচালিত? অতীতে আমার যে সমস্যাগুলির কারণ হয়েছিল তা হ'ল org.codehaus.jacksonএটি প্যাকেজ থেকে টীকাগুলি উপলব্ধি না করে ব্যবহার করা। আপনার সমস্ত আমদানি এসেছে কিনা তা নিশ্চিত করুন com.fasterxml.jackson
হেলদার পেরেইরা

1

আমি সঠিক একই সমস্যা ছিল। আমি এই পোস্টে সমাধানটি পেয়েছি: জ্যাকসন বা এর বিকল্পগুলি ব্যবহার করে জেএসএন গাছকে সমতল শ্রেণিতে পার্স করুন

শেষ উত্তরটি দেখুন। যে জসননোডকে প্যারামিটার হিসাবে গ্রহণ করে এবং স্ট্রিং সম্পত্তি সেট করার জন্য জসননোডে টস স্ট্রিং পদ্ধতিটি কল করে এমন সম্পত্তিটির জন্য একটি কাস্টম সেটটার সংজ্ঞায়িত করে, এটি সব কার্যকর হয়।


1

কোনও অবজেক্ট ব্যবহার করা উভয়ভাবেই সূক্ষ্মভাবে কাজ করে ... এই পদ্ধতিতে দুটি সময়ে কাঁচা মানটি ডিসায়রিয়ালের কিছুটা ওভারহেড থাকে।

ObjectMapper mapper = new ObjectMapper();
RawJsonValue value = new RawJsonValue();
value.setRawValue(new RawHello(){{this.data = "universe...";}});
String json = mapper.writeValueAsString(value);
System.out.println(json);
RawJsonValue result = mapper.readValue(json, RawJsonValue.class);
json = mapper.writeValueAsString(result.getRawValue());
System.out.println(json);
RawHello hello = mapper.readValue(json, RawHello.class);
System.out.println(hello.data);

RawHello.java

public class RawHello {

    public String data;
}

RawJsonValue.java

public class RawJsonValue {

    private Object rawValue;

    public Object getRawValue() {
        return rawValue;
    }

    public void setRawValue(Object value) {
        this.rawValue = value;
    }
}

1

আমার অনুরূপ সমস্যা ছিল, তবে প্রচুর জেএসএন ইটেন ( List<String>) দিয়ে একটি তালিকা ব্যবহার করা হচ্ছে ।

public class Errors {
    private Integer status;
    private List<String> jsons;
}

আমি @JsonRawValueটীকাটি ব্যবহার করে সিরিয়ালাইজেশন পরিচালনা করেছি । তবে ডিসিরিয়ালাইজেশনের জন্য আমাকে রায়ের পরামর্শের ভিত্তিতে একটি কাস্টম ডিসরিয়ালাইজার তৈরি করতে হয়েছিল।

public class Errors {

    private Integer status;

    @JsonRawValue
    @JsonDeserialize(using = JsonListPassThroughDeserialzier.class)
    private List<String> jsons;

}

নীচে আপনি আমার "তালিকা" ডিসরিওলাইজার দেখতে পাচ্ছেন।

public class JsonListPassThroughDeserializer extends JsonDeserializer<List<String>> {

    @Override
    public List<String> deserialize(JsonParser jp, DeserializationContext cxt) throws IOException, JsonProcessingException {
        if (jp.getCurrentToken() == JsonToken.START_ARRAY) {
            final List<String> list = new ArrayList<>();
            while (jp.nextToken() != JsonToken.END_ARRAY) {
                list.add(jp.getCodec().readTree(jp).toString());
            }
            return list;
        }
        throw cxt.instantiationException(List.class, "Expected Json list");
    }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.