Skip to content
This repository has been archived by the owner on Aug 20, 2021. It is now read-only.

json toBean传入参数首字母为大写时转化的值为空的问题 #509

Closed
shade41-code opened this issue Oct 31, 2016 · 5 comments
Closed
Assignees
Milestone

Comments

@shade41-code
Copy link

shade41-code commented Oct 31, 2016

在和第三方对接的时候,对方给到的参数是json格式的,但是json字符串中每个参数的名称首字母是大写的,json字符串和实体类如下:

{
    "MemberNo":"11105000009",
    "Name":null,
    "Gender":"",
    "Phone":"15036334567",
    "Email":null,
    "Birthday":""
}

public class CrmMemberInfoCommand implements Serializable{
    /** 会员编号 */
    private String memberNo;

    /** 姓名/昵称 */
    private String name;

    /** 电话号码 */
    private String phone;

    /** 性别:男;女 */
    private String gender;

    /** 生日:Format:yyyy-MM-dd */
    private String birthday;

    /** 邮箱 */
    private String email;

     // setter getter
}

直接使用@venusdrogon feilong jar中的JsonUtil.toBean(Object json,Class rootClass);
会抛出异常,例如

et.sf.json.JSONException: java.lang.NoSuchMethodException: Unknown property 'MemberNo' on class 'class com.store.command.crm.CrmMemberInfoCommand'
	at net.sf.json.util.PropertySetStrategy$DefaultPropertySetStrategy._setProperty(PropertySetStrategy.java:69)
	at net.sf.json.util.PropertySetStrategy$DefaultPropertySetStrategy.setProperty(PropertySetStrategy.java:60)
	at net.sf.json.util.PropertySetStrategy$DefaultPropertySetStrategy.setProperty(PropertySetStrategy.java:45)
	at com.feilong.tools.jsonlib.util.PropertyStrategyWrapper.setProperty(PropertyStrategyWrapper.java:61)
	at net.sf.json.util.PropertySetStrategy.setProperty(PropertySetStrategy.java:40)
	at net.sf.json.JSONObject.setProperty(JSONObject.java:1394)
	at net.sf.json.JSONObject.toBean(JSONObject.java:429)
	at com.store.util.LevisJsonUtil.toBean(LevisJsonUtil.java:87)
	at com.store.crm.LevisCrmBuilderTest.memberQueryTest(LevisCrmBuilderTest.java:90)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:606)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
@shade41-code
Copy link
Author

在网上找了之后发现,在将json转换为CrmMemberInfoCommand 对象在初始化JsonConfig的时候,需要设置JsonConfig的JavaIdentifierTransformer属性并重写JavaIdentifierTransformer对象的transformToJavaIdentifier方法,将每个参数名称首字母改为小写,事例代码如下:

    @Test
    public void memberQueryTest(){
        Map<String,String> map=new HashMap<String,String>();
        map.put("MemberNo", "11105000009");
        map.put("Name", "test");
        map.put("Gender", "男");
        map.put("Phone", "1501234567");
        map.put("Email", "test@qq.com");
        map.put("Birthday", "2000-01-01");
        JSONObject jsonObject = JSONObject.fromObject(map);
        JsonConfig jsonConfig = new JsonConfig();        
        jsonConfig.setJavaIdentifierTransformer(new JavaIdentifierTransformer(){
            @Override
            public String transformToJavaIdentifier(String str){
                return str.substring(0, 1).toLowerCase()+ str.substring(1);
            }
        });
        jsonConfig.setCycleDetectionStrategy(CycleDetectionStrategy.LENIENT);
        jsonConfig.setIgnoreDefaultExcludes(false);
        jsonConfig.registerJsonValueProcessor(Date.class, new DateJsonValueProcessor(DatePattern.COMMON_DATE_AND_TIME));
        jsonConfig.setAllowNonStringKeys(true);
        jsonConfig.setRootClass(CrmMemberInfoCommand.class);
        jsonConfig.setPropertySetStrategy(new PropertyStrategyWrapper(PropertySetStrategy.DEFAULT));
        CrmMemberInfoCommand crmMemberInfoCommand=(CrmMemberInfoCommand) JSONObject.toBean(jsonObject, jsonConfig);        
        LOGGER.info(JsonUtil.format(crmMemberInfoCommand));        
    }

输出

{
        "birthday": "2000-01-01",
        "phone": "1501234567",
        "email": "test@qq.com",
        "name": "test",
        "gender": "男",
        "memberNo": "11105000009"
 }

@venusdrogon venusdrogon self-assigned this Oct 31, 2016
@venusdrogon
Copy link
Collaborator

net.sf.json.util.JSONUtils.convertToJavaIdentifier(String, JsonConfig)

image


net.sf.json.util.JSONUtils.convertToJavaIdentifier(String, JsonConfig)

image

默认实现:

image

@venusdrogon venusdrogon added this to the 1.9.4 milestone Oct 31, 2016
@venusdrogon
Copy link
Collaborator

venusdrogon commented Oct 31, 2016

写了一个版本

    @Test
    public void testToBean2(){
        String json = "{'MemberNo':'11105000009','Name':null,'Gender':'','Phone':'15036334567','Email':null,'Birthday':''}";

        JsonToJavaConfig jsonToJavaConfig = new JsonToJavaConfig();
        jsonToJavaConfig.setRootClass(CrmMemberInfoCommand.class);
        jsonToJavaConfig.setJavaIdentifierTransformer(UncapitalizeJavaIdentifierTransformer.UNCAPITALIZE);

        CrmMemberInfoCommand crmMemberInfoCommand = JsonUtil.toBean(json, jsonToJavaConfig);

        LOGGER.debug(JsonUtil.format(crmMemberInfoCommand));

    }

当然,也提供了便捷的构造函数 ,一行代码搞定

 String json = "{'MemberNo':'11105000009','Name':null,'Gender':'','Phone':'15036334567','Email':null,'Birthday':''}";

 CrmMemberInfoCommand crmMemberInfoCommand = JsonUtil.toBean(json, new JsonToJavaConfig(CrmMemberInfoCommand.class, UNCAPITALIZE));

@venusdrogon
Copy link
Collaborator

venusdrogon commented Oct 31, 2016

  1. net.sf.json.JsonConfig.setCycleDetectionStrategy(CycleDetectionStrategy)
  2. net.sf.json.JsonConfig.setIgnoreDefaultExcludes(boolean)
  3. net.sf.json.JsonConfig.registerJsonValueProcessor(Class, JsonValueProcessor)
  4. net.sf.json.JsonConfig.setAllowNonStringKeys(boolean)

上述都是 java to json 的方法 ,此处可以不使用

feilong 重新修订了方法名称

com.feilong.tools.jsonlib.JsonHelper.buildDefaultJavaToJsonConfig()

    /**
     * 默认的java to json JsonConfig.
     * 
     * <h3>含有以下的特性:</h3>
     * <blockquote>
     * <ol>
     * <li>{@link CycleDetectionStrategy#LENIENT} 避免循环引用</li>
     * <li>no IgnoreDefaultExcludes,默认过滤几个key "class", "declaringClass","metaClass"</li>
     * <li>
     * {@link DateJsonValueProcessor},如果是日期,自动渲染成 {@link DatePattern#COMMON_DATE_AND_TIME} 格式类型,如有需要可以使用
     * {@link JavaToJsonConfig#setPropertyNameAndJsonValueProcessorMap(Map)}覆盖此属性
     * </li>
     * <li>AllowNonStringKeys,允许非 string类型的key</li>
     * </ol>
     * </blockquote>
     *
     * @return the default json config
     * @see see net.sf.json.JsonConfig#DEFAULT_EXCLUDES
     * @see net.sf.json.util.CycleDetectionStrategy#LENIENT
     * 
     * @see <a href="http://feitianbenyue.iteye.com/blog/2046877">通过setAllowNonStringKeys解决java.lang.ClassCastException: JSON keys must be
     *      strings</a>
     */
    static JsonConfig buildDefaultJavaToJsonConfig(){
        JsonConfig jsonConfig = new JsonConfig();

        //see net.sf.json.JsonConfig#DEFAULT_EXCLUDES
        //默认会过滤的几个key "class", "declaringClass","metaClass"  
        jsonConfig.setIgnoreDefaultExcludes(false);

        // java.lang.ClassCastException: JSON keys must be strings
        // see http://feitianbenyue.iteye.com/blog/2046877
        jsonConfig.setAllowNonStringKeys(true);

        //排除,避免循环引用 There is a cycle in the hierarchy!
        //Returns empty array and null object
        jsonConfig.setCycleDetectionStrategy(CycleDetectionStrategy.LENIENT);

        // 注册日期处理器
        jsonConfig.registerJsonValueProcessor(Date.class, new DateJsonValueProcessor(COMMON_DATE_AND_TIME));
        return jsonConfig;
    }

@venusdrogon venusdrogon modified the milestone: 1.9.4 Nov 2, 2016
@venusdrogon
Copy link
Collaborator

单元测试

    @Test
    public void testToBeanWithUncapitalizeJavaIdentifierTransformer(){
        String json = "{'MemberNo':'11105000009','Name':null,'Gender':'','Phone':'15036334567','Email':null,'Birthday':''}";

        CrmMemberInfoCommand crmMemberInfoCommand = JsonUtil.toBean(json, new JsonToJavaConfig(CrmMemberInfoCommand.class, UNCAPITALIZE));

        assertThat(crmMemberInfoCommand, allOf(//
                        hasProperty("memberNo", is("11105000009")),
                        hasProperty("name", is(nullValue())),
                        hasProperty("gender", is("")),
                        hasProperty("phone", is("15036334567")),
                        hasProperty("email", is(nullValue())),
                        hasProperty("birthday", is(""))
        //        
        ));
    }

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants