json序列化,少了自己的属性

public class Brand extends BaseBrand<Brand> {

private Company company;

private Category category;


      toString();

}

public void listData(){

Page<Brand> projectPage = srv.paginate(getParaToInt("pageNo", 1));

PageInfo<Brand> pageInfo = WebKit.convertPage(projectPage);

Result result=WebKit.buildDataResult(pageInfo);

renderJson(result);

}

自己定义的Result,Brand对象里 有 2个属性,有值的。

但是 调用renderJons之后,返回之后,却只有Model几个标准的属性。

怎么丢失了呢?

有大佬支持就是好啊,还很及时~


评论区

fansunion

2018-09-01 17:30

序列化方式使用的是 me.setJsonFactory(MixedJsonFactory.me());。
如果改为 FastJsonFactory.me(),Brand表创建时间 createTime 数据库明明是 datetime,却报错了
java.lang.ClassCastException: java.lang.String cannot be cast to java.util.Date
at com.jtn.bgj.common.model.base.BaseCategory.getCreateTime(BaseCategory.java:33)

BaseCategory{
public java.util.Date getCreateTime() {
return get("createTime");
}
}

理论和实战 区别还真是大,遇到好多问题。
JFinal需要做几个项目才能搞定 所有问题。

JFinal

2018-09-01 17:36

Brand 光定义两个属性不够的,需要有相应的 getter 方法配套,因为 fastjson 是通过你的 getter 方法进行 json 转换的

如果用 jfinal 自己的 json 转换工具,则需要 put("company", company) 这样将数据 put 进去才能转换,总的来说没有必要定义属性

此外, createTime 转换错误,你看这个 String 数据是多哪里来的? 是不是自己放进去的? 还是说从数据库来的时候就是 String ?

一般来说 date 数据从数据库出来仍然是 Date 类型,而不会无故成为 String 类型,这个通过单步调试很容易知道类型为啥不对

fansunion

2018-09-01 17:49

@JFinal MixedJsonFactory.me(),Brand定义了 get和set也不行。 场景是这样的:品牌表,属于某个公司,数据库model只定义了 id,我手动再定义了 1个关联实体,company对象。 list查询之后,批量查询 公司,放到对应的 brand 里。
序列化确实没有 company 手动增加的属性,试试put吧。

fansunion

2018-09-01 17:51

@JFinal 放到put里, 好了。确实 不需要再自定义属性。get和set方法就行了,用父类的attr统一维护 所有变量。
public void setCompany(Company company) {
//this.company = conpany;
super.put("company", company);
}

fansunion

2018-09-01 18:07

@JFinal 序列化麻烦再支持下哦。
public void configConstant(Constants me) {
me.setDevMode(p.getBoolean("devMode", true));
//me.setJsonFactory(MixedJsonFactory.me());
me.setJsonFactory(FastJsonFactory.me());
}
用MixedJsonFactory 序列化自定义的Result对象(里面有Brand列表,createTime是datetime)是ok的,但是换成FastJsonFactory在序列化的时候,就 报错了。

[ERROR]-[Thread: qtp1418334255-34]-[com.jfinal.core.ActionHandler.handle()]: /admin/brand/listData
java.lang.ClassCastException: java.lang.String cannot be cast to java.util.Date
at com.jtn.bgj.common.model.base.BaseCategory.getCreateTime(BaseCategory.java:33)
at com.alibaba.fastjson.serializer.ASMSerializer_5_Category.write(Unknown Source)
at com.alibaba.fastjson.serializer.ASMSerializer_3_Brand.write(Unknown Source)
at com.alibaba.fastjson.serializer.JSONSerializer.writeWithFieldName(JSONSerializer.java:304)
at com.alibaba.fastjson.serializer.JSONSerializer.writeWithFieldName(JSONSerializer.java:282)
at com.alibaba.fastjson.serializer.ASMSerializer_2_PageInfo.write(Unknown Source)
at com.alibaba.fastjson.serializer.JSONSerializer.writeWithFieldName(JSONSerializer.java:304)
at com.alibaba.fastjson.serializer.ASMSerializer_1_Result.write(Unknown Source)
at com.alibaba.fastjson.serializer.JSONSerializer.write(JSONSerializer.java:275)
at com.alibaba.fastjson.JSON.toJSONString(JSON.java:648)
at com.alibaba.fastjson.JSON.toJSONStringWithDateFormat(JSON.java:582)
at com.jfinal.json.FastJson.toJson(FastJson.java:44)
at com.jfinal.kit.JsonKit.toJson(JsonKit.java:28)
at com.jfinal.render.JsonRender.(JsonRender.java:125)
at com.jfinal.render.RenderFactory.getJsonRender(RenderFactory.java:103)
at com.jfinal.core.Controller.renderJson(Controller.java:1093)
at com.jtn.bgj._admin.brand.BrandAdminController.listData(BrandAdminController.java:25)
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:483)
at com.jfinal.aop.Invocation.invoke(Invocation.java:73)
at com.jtn.bgj._admin.common.PjaxInterceptor.intercept(PjaxInterceptor.java:15)
at com.jfinal.aop.Invocation.invoke(Invocation.java:67)
at com.jfinal.core.ActionHandler.handle(ActionHandler.java:78)
at com.jfinal.plugin.druid.DruidStatViewHandler.handle(DruidStatViewHandler.java:81)
at com.jfinal.core.JFinalFilter.doFilter(JFinalFilter.java:73)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1307)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:453)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:560)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:231)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1072)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:382)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1006)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116)
at org.eclipse.jetty.server.Server.handle(Server.java:365)
at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:485)
at org.eclipse.jetty.server.AbstractHttpConnection.content(AbstractHttpConnection.java:937)
at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.content(AbstractHttpConnection.java:998)
at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:856)
at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:240)
at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:82)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:628)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:52)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543)
at java.lang.Thread.run(Thread.java:745)

fansunion

2018-09-01 18:08

Brand的Category的 createTime报的错。
com.jtn.bgj.common.model.base.BaseCategory.getCreateTime(BaseCategory.java:33)


@SuppressWarnings("serial")
public class Brand extends BaseBrand {

public Company getCompany() {
return super.get("company");
}

public void setCompany(Company company) {
super.put("company", company);
}

public Category getCategory() {
return super.get("category");
}

public void setCategory(Category category) {
super.put("category", category);
}

@Override
public String toString() {
return "Brand [toString()=" + super.toString() + "]";
}

}

fansunion

2018-09-01 18:31

public static void main(String[] args) {
Category category = new Category();
category.setCreateTime(new Date());
String s= JSON.toJSONString(category);
System.out.println(s);

Brand brand = new Brand();
brand.setCategory(category);
String s2= JSON.toJSONString(category);
System.out.println(s2);
}
输出结果,序列化成功
{"createTime":1535797596584}
{"createTime":1535797596584}

这个问题有点奇怪了,我自己再试试看看吧。

JFinal

2018-09-01 18:41

MixedJsonFactory 转 json string 时用的 JFinalJson,反过来转成 Model/Bean 时用的 FastJson,所以你在使用它时,仍然要用 put(...),否则直接使用 FastJsonFactory 即可,这个在文档中有过明确的说明:
http://www.jfinal.com/doc/12-3

String 到 Date 的类型转换错误还是没有找到源头,getCreateTime(...) 这个地方仅仅是异常抛出的地方,根本不是数据的源头

JFinal

2018-09-01 18:41

我很怀疑你的数据库字段本来就是 varchar,而你却误以为是 date/datetime

JFinal

2018-09-01 18:45

补充一个有用的点: JFinalJson 转 json 时不依赖于 getter 方法,而是将 Model.attrs 这个 Map 中的值转成 json,所以这就支持了你 sql 关联查询时查出来的字段

这类关联查出来的字段在 Model/Bean 中是没有 getter 方法的,相当于动态化了

例如,你在 Article 这个 model 中没有定义 getUserName() 这个方法,但可以这样查询:
select a.*, u.userName from article a inner join user u on a.userId = u.id

上面是一个关联查询,在转 json 时会将 u.userName 这个关联过来的属性转换成 json,而这个功能在一般的 json 转换工具中是不可能实现的

JFinal

2018-09-01 18:47

再补充一个知识点:
配置 MixedJsonFactory、FastJsonFactory 等等 factory 以后,并不意思着不能使用其它类型的 json 转换工具了,还可以临时这么来用:
JFinalJson.getJson().toJson(...);
FastJson.getJson().toJson(...);

也就是说 factory 是配置默认,当不想使用默认时可以这样:
String json = JFinalJson.getJson().toJson(...);
renderJson(json);

fansunion

2018-09-01 19:09

感谢波哥(没错吧)没有放弃治疗我。搞定了。
Brand实体,有Company和Category,Company的createTime确实是 varchar,改为 datetime就好了。(MixedJson没有报错,FastJson报错)。

诡异的地方在于,category表的createTime 的确是 datetime,但是 为啥总是提示我 BaseCategory的createTime报错呢?
确认看了下日志,
2018-09-01 18:19:50
[ERROR]-[Thread: qtp1418334255-32]-[com.jfinal.core.ActionHandler.handle()]: /admin/brand/listData
java.lang.ClassCastException: java.lang.String cannot be cast to java.util.Date
at com.jtn.bgj.common.model.base.BaseCategory.getCreateTime(BaseCategory.java:33)

2018-09-01 18:22:49
[ERROR]-[Thread: qtp1418334255-29]-[com.jfinal.core.ActionHandler.handle()]: /admin/brand/listData
java.lang.ClassCastException: java.lang.String cannot be cast to java.util.Date
at com.jtn.bgj.common.model.base.BaseCategory.getCreateTime(BaseCategory.java:33)


2018-09-01 18:30:22
[ERROR]-[Thread: qtp1418334255-33]-[com.jfinal.core.ActionHandler.handle()]: /admin/brand/listData
java.lang.ClassCastException: java.lang.String cannot be cast to java.util.Date
at com.jtn.bgj.common.model.base.BaseCategory.getCreateTime(BaseCategory.java:33)

18:30去吃饭了,吃过饭后,把 Company表的 createTime从 varhcar改为 datetime,就可以了。

这个时候,我再从datetime改回varchar,提示报错:

2018-09-01 18:58:09
[ERROR]-[Thread: qtp1418334255-30]-[com.jfinal.core.ActionHandler.handle()]: /admin/brand/listData
java.lang.ClassCastException: java.lang.String cannot be cast to java.util.Date
at com.jtn.bgj.common.model.base.BaseCompany.getCreateTime(BaseCompany.java:65)

这个时候, 错误提示 就是准确的是“BaseCompany”。
我没有使用缓存。
很诡异~~~
--------------------------------------------------------------------------------
感谢波哥指点~~~

fansunion

2018-09-01 19:31

坚决从正面解决问题,又看了一会。

“String 到 Date 的类型转换错误还是没有找到源头,getCreateTime(...) 这个地方仅仅是异常抛出的地方,根本不是数据的源头 回复

JFinal 09-01 18:41
我很怀疑你的数据库字段本来就是 varchar,而你却误以为是 date/datetime”

这2个来自 非当事人视角的提示,非常关键。


来回从dateTime和varchar之间互相改,可以复现 错误提示
“java.lang.ClassCastException: java.lang.String cannot be cast to java.util.Date
at com.jtn.bgj.common.model.base.BaseCategory.getCreateTime(BaseCategory.java:33)”。

只要能复现,说明 代码肯定哪里有问题。

然后看日志:
--------------------------------------------------------------------------------
Sql: select count(*) from brand
Sql: select * from brand order by id desc limit 0, 10
Sql: select *
from company
where id in(
1
, 2
)

Sql: select *
from company
where id in(
2
, 5
, 4
, 3
)
发现4个查询中,最后2个 批量in查询,竟然都是从 company。
终于定位到问题源头。


---------------------------------------
根本原因:Company表的createTime的确是 varchar的。(数据库设计时,默认 没有改)
category sql查询的 是 company表。(in查询 不太熟悉,搞定1个之后,复制粘贴的,表名没有改 )
---------------------------------------

波哥威武~
(*^__^*)
下班~

fansunion

2018-09-01 19:50

FastJson还有 循环引用的问题,搞了个 扩展,就好了。 分享了。下班2~

JFinal

2018-09-01 20:27

@fansunion 数据库字段类型是 varchar 的时候,你可以重新运行一下 jfinal 生成器,那么相应的 getter setter 方法中的类型会跟着改变

此外,建议所有字段使用驼峰命名,这样就可以让 JFinalJson、FastJson 转 json string 时的格式统一了,无论是通过 getter 方法还是 Model.attrs 的 Map 转都一样的结果

fansunion

2018-09-01 21:02

@JFinal 理解,看到JFinal都这么搞,我就放心了。 尽可能简化代码,数据库 按照java命名搞, Service只需要实现类,根本不需要再多定义一个借口。启动速度 又非常快。比Spring那一套快多了。 目前做的项目还不多,已经知道的JFinal生态不如Spring。后面遇到问题 再解决。

JFinal

2018-09-02 10:59

@fansunion jfinal 生态在国产 web + orm 框架中已经是最好的了,往后的世界不可能只有 spring 一家,jfinal 的定位与 spring 在很多方面几乎是相反的

jfinal 追求简而精,追求让用户代码量最小、学习成本最低、开发效率最高。jfinal 自身的代码量很小,解决问题时比 spirng 要容易多了,基本就是单步调试往下跟两层就知道原因了,而 spring 之下你跟踪七八层还找不着北呢

热门反馈

扫码入社