JSONObject转换为对象时,转换后的对象为空

将JSONObject转换为对象时,发现转换后的对象为空,代码如下

@Getter
@Setter
@Entity
@Table(name = "image")
@Accessors(chain = true)
public class MqHouseImage {
    @Id
    @Column(name = "id")
    private String image_id;
    //图片地址
    private String url = null;
    
}
    @Test
    public void t(){
        String image = "{\"image_id\":\"22\",\"url\":\"eagle/3257/house/2020/05/22/16/6fe357ae42d155042aeb4157c6a31a5e383501ae266.jpg\"}";
        JSONObject jsonObject = JSONObject.fromObject(image);
        MqHouseImage mqHouseImage = (MqHouseImage) JSONObject.toBean(jsonObject, MqHouseImage.class);
        System.out.println(mqHouseImage);
    }

运行结果:

2020-05-28 17:54:04.847  INFO 6788 --- [           main] net.sf.json.JSONObject                   : Property 'image_id' of class com.web.website.entity.toqj.HouseImage has no write method. SKIPPED.
2020-05-28 17:54:04.847  INFO 6788 --- [           main] net.sf.json.JSONObject                   : Property 'url' of class com.web.website.entity.toqj.HouseImage has no write method. SKIPPED.
com.web.website.entity.toqj.HouseImage@74889ebe

debug 

 

 

发现BeanUtils底层使用了PropertyDescriptor反射获取属性,通过PropertyDescriptor的getWriteMethod()方法获取属性的setter方法,最后通过setter方法给属性赋值, getWriteMethod()方法返回了 null(也就是获取不到setter方法),导致后续没有执行赋值

getWriteMethod()源码

public synchronized Method getWriteMethod() {
        Method writeMethod = this.writeMethodRef.get();
        if (writeMethod == null) {
            Class<?> cls = getClass0();
            if (cls == null || (writeMethodName == null && !this.writeMethodRef.isSet())) {
                // The write method was explicitly set to null.
                return null;
            }

            // We need the type to fetch the correct method.
            Class<?> type = getPropertyType0();
            if (type == null) {
                try {
                    // Can't use getPropertyType since it will lead to recursive loop.
                    type = findPropertyType(getReadMethod(), null);
                    setPropertyType(type);
                } catch (IntrospectionException ex) {
                    // Without the correct property type we can't be guaranteed
                    // to find the correct method.
                    return null;
                }
            }

            if (writeMethodName == null) {
                writeMethodName = Introspector.SET_PREFIX + getBaseName();
            }

            Class<?>[] args = (type == null) ? null : new Class<?>[] { type };
            writeMethod = Introspector.findMethod(cls, writeMethodName, 1, args);
            if (writeMethod != null) {
                if (!writeMethod.getReturnType().equals(void.class)) {
                    writeMethod = null;
                }
            }
            try {
                setWriteMethod(writeMethod);
            } catch (IntrospectionException ex) {
                // fall through
            }
        }
        return writeMethod;
    }

 通过分析getWriteMethod()源码,发现setter方法的返回值必须是void,否则返回null

if (writeMethod != null) {
    if (!writeMethod.getReturnType().equals(void.class)) {
        writeMethod = null;
    }
}

使用refactor 菜单的 delombok 选项将lombok 注解转换成源码发现,@Accessors(chain = true)生成的setter方法返回的不是void而是对象本身,源码如下

@Entity
@Table(name = "image")
@Accessors(chain = true)
public class HouseImage {
    @Id
    @Column(name = "id")
    private String image_id;
    //图片地址
    private String url = null;

    public String getImage_id() {
        return this.image_id;
    }

    public String getUrl() {
        return this.url;
    }

    public HouseImage setImage_id(String image_id) {
        this.image_id = image_id;
        return this;
    }

    public HouseImage setUrl(String url) {
        this.url = url;
        return this;
    }
}

:@Accessors(chain = true) 注解导致JavaBean生成的 setter 方法不被 PropertyDescriptor 识别,导致获取 setter为null

进一步验证@Builder,发现需添加@NoArgsConstructor @AllArgsConstructor,否则会报如下异常

net.sf.json.JSONException: java.lang.NoSuchMethodException: com.web.website.entity.toqj.HouseImage.<init>()

	at net.sf.json.JSONObject.toBean(JSONObject.java:288)
	at net.sf.json.JSONObject.toBean(JSONObject.java:233)
	at com.web.website.unit.image.MapInfoUnitTest.t(MapInfoUnitTest.java:65)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	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.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:73)
	at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:83)
	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
Caused by: java.lang.NoSuchMethodException: com.web.website.entity.toqj.HouseImage.<init>()
	at java.lang.Class.getConstructor0(Class.java:3082)
	at java.lang.Class.getDeclaredConstructor(Class.java:2178)
	at net.sf.json.util.NewBeanInstanceStrategy$DefaultNewBeanInstanceStrategy.newInstance(NewBeanInstanceStrategy.java:55)
	at net.sf.json.JSONObject.toBean(JSONObject.java:282)
	... 32 more

使用@Builder源码

public class HouseImage {
    @Id
    @Column(name = "id")
    private String image_id;
    //图片地址
    private String url = null;

    HouseImage(String image_id, String url) {
        this.image_id = image_id;
        this.url = url;
    }

    public static HouseImageBuilder builder() {
        return new HouseImageBuilder();
    }

    public String getImage_id() {
        return this.image_id;
    }

    public String getUrl() {
        return this.url;
    }

    public void setImage_id(String image_id) {
        this.image_id = image_id;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public static class HouseImageBuilder {
        private String image_id;
        private String url;

        HouseImageBuilder() {
        }

        public HouseImage.HouseImageBuilder image_id(String image_id) {
            this.image_id = image_id;
            return this;
        }

        public HouseImage.HouseImageBuilder url(String url) {
            this.url = url;
            return this;
        }

        public HouseImage build() {
            return new HouseImage(image_id, url);
        }

        public String toString() {
            return "HouseImage.HouseImageBuilder(image_id=" + this.image_id + ", url=" + this.url + ")";
        }
    }
}

 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值