CSUG / HouseMD

HouseMD is an awesome diagnosing tool better than BTrace
http://csug.github.io/HouseMD/
Apache License 2.0
700 stars 218 forks source link

trace -d ERROR:com.alibaba.fastjson.JONException:illegal getter #86

Closed ferdiknight closed 12 years ago

ferdiknight commented 12 years ago
/**
 *
 * @author ferdinand
 */
public class RelationChangeEvent implements RelationEvent
{
    private long srcuid;//源用户id
    private long targetid;//目标用户id
    private RelationType type;//关系类型
    private RelationAction action;//关系操作
    private ActionPoint point;//关系操作指针
    private long timestamp;//时间戳
    private String src;//来源
    private Map<String,String> attrs;//meta属性

    public RelationChangeEvent(){}

    public RelationChangeEvent(long srcuid, long targetid, RelationType type, RelationAction action, ActionPoint point, long timestamp, String src)
    {
        this.srcuid = srcuid;
        this.targetid = targetid;
        this.type = type;
        this.action = action;
        this.point = point;
        this.timestamp = timestamp;
        this.src = src;
    }

    public RelationChangeEvent addAttr(String key,String value)
    {
        this.attrs.put(key, value);
        return this;
    }

    public RelationAction getAction()
    {
        return action;
    }

    public RelationChangeEvent setAction(RelationAction action)
    {
        this.action = action;
        return this;
    }

    public Map<String, String> getAttrs()
    {
        return attrs;
    }

    public RelationChangeEvent setAttrs(Map<String, String> attrs)
    {
        this.attrs = attrs;
        return this;
    }

    public ActionPoint getPoint()
    {
        return point;
    }

    public RelationChangeEvent setPoint(ActionPoint point)
    {
        this.point = point;
        return this;
    }

    public String getSrc()
    {
        return src;
    }

    public RelationChangeEvent setSrc(String src)
    {
        this.src = src;
        return this;
    }

    public long getSrcuid()
    {
        return srcuid;
    }

    public RelationChangeEvent setSrcuid(long srcuid)
    {
        this.srcuid = srcuid;
        return this;
    }

    public long getTargetid()
    {
        return targetid;
    }

    public RelationChangeEvent setTargetid(long targetid)
    {
        this.targetid = targetid;
        return this;
    }

    public long getTimestamp()
    {
        return timestamp;
    }

    public RelationChangeEvent setTimestamp(long timestamp)
    {
        this.timestamp = timestamp;
        return this;
    }

    public RelationType getType()
    {
        return type;
    }

    public RelationChangeEvent setType(RelationType type)
    {
        this.type = type;
        return this;
    }    

}

目标事件对象,setter getter使用了append模式,但是我系统内消息服务的时候就是用的fastjson做json序列化,fastjson-1.1.18

RelationEvent event = JSONUtils.parserObject(json, RelationEvent.class);

public static <T extends Object> T parserObject(String jsonString,Class<T> clazz)
{
        return JSON.parseObject(jsonString, clazz);
}

public void send(RelationEvent event)
{
        String json = JSONObject.toJSONString(event);
        send(channel, "change", json);
}

RelationEvent是一个完全没有实现的interface

public interface RelationEvent
{

}
zhongl commented 12 years ago

呃, 我看不太懂你问题的重点是什么?

我的假设是, 你使用trace -d 跟踪某个方法(能够说明是哪个吗?), 然后输出错误com.alibaba.fastjson.JONException:illegal getter , 那么现在如果是我, 我会去问fastjson的作者@wenshao 什么情况会抛出这样的异常.

或者, 请查看fastjson的源码找寻原因.

PS: 如果你是使用版本0.2.4, 请在出现上面的错误后, 使用last命令查看错误信息的完整堆栈帮助分析原因.

PS: 下次提交issue, 麻烦将代码内容使用下面的Markdown语法优化一下显示, 方便我阅读, 谢谢.

```java
some code
ferdiknight commented 12 years ago

啊,抱歉,是我没表述清楚,那个fastjson的异常并不是来自我的代码,而是trace -d 在输出时序列化RelationChangeEvent这个参数对象的时候报的异常,是housemd抛出的异常

然后我本身对这个事件对象做序列化的时候也是用的fastjson,所以现在想请问下housemd在trace -d的时候是用的fastjson的哪个方法序列化对象的

跟踪的 public void onRelationChange(RelationEvent event) 这样一个方法,RelationChangeEvent 是 RelationEvent 的实现

现在的现象就是 trace是没问题的,但是-d 就会抛出这个异常,我猜大概是-d 时housemd输出是用标准的java bean格式去序列化的,所以append形式的get方法会抛异常

ferdiknight commented 12 years ago

呃,点错按钮了……

ferdiknight commented 12 years ago

com.alibaba.fastjson.JSONObject.invoke(JSONObject.java:397) $Proxy10.toString(Unknown Source) java.lang.String.valueOf(String.java:2826) scala.collection.mutable.StringBuilder.append(StringBuilder.scala:187) scala.collection.TraversableOnce$$anonfun$addString$1.apply(TraversableOnce.scala:300) scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:34) scala.collection.mutable.ArrayOps.foreach(ArrayOps.scala:38) scala.collection.TraversableOnce$class.addString(TraversableOnce.scala:298) scala.collection.mutable.ArrayOps.addString(ArrayOps.scala:38) scala.collection.TraversableOnce$class.mkString(TraversableOnce.scala:263) scala.collection.mutable.ArrayOps.mkString(ArrayOps.scala:38) com.github.zhongl.housemd.command.DetailWriter.write(Trace.scala:155) com.github.zhongl.housemd.command.Trace$$anon$1.exitWith(Trace.scala:71) com.github.zhongl.housemd.command.TransformCommand$$anon$2.exitWith(TransformCommand.scala:61) com.github.zhongl.housemd.instrument.Transform$$anonfun$handleAdviceEvent$1.apply(Transform.scala:87) com.github.zhongl.housemd.instrument.Transform$$anonfun$handleAdviceEvent$1.apply(Transform.scala:83) scala.actors.Actor$class.receiveWithin(Actor.scala:630) scala.actors.ActorProxy.receiveWithin(ActorProxy.scala:20) scala.actors.Actor$.receiveWithin(Actor.scala:208) com.github.zhongl.housemd.instrument.Transform.handleAdviceEvent(Transform.scala:83) com.github.zhongl.housemd.instrument.Transform.apply(Transform.scala:67) com.github.zhongl.housemd.command.TransformCommand.run(TransformCommand.scala:65) com.github.zhongl.yascli.Suite$class.run(Suite.scala:51) com.github.zhongl.yascli.Shell.run(Shell.scala:27) com.github.zhongl.yascli.Shell.parse$1(Shell.scala:50) com.github.zhongl.yascli.Shell.interact(Shell.scala:58) com.github.zhongl.yascli.Shell.main(Shell.scala:33) com.github.zhongl.housemd.duck.Telephone.run(Telephone.scala:54) java.lang.Thread.run(Thread.java:662)

zhongl commented 12 years ago

根据异常堆栈信息:

com.github.zhongl.housemd.command.DetailWriter.write(Trace.scala:155)

可以看出trace -d在尝试输出方法参数值, 但HouseMD不会采用Java Bean的方式序列化对象, 而是调用值对象的toString()方法.

根据提供异常堆栈的信息前两行:

com.alibaba.fastjson.JSONObject.invoke(JSONObject.java:397) $Proxy10.toString(Unknown Source)

你跟踪的应用中, 可能存在有AOP的机制改写toString()方法的实现, 即调用fastjson来输出对象的字符串内容, 但fastjson报错了.

所以, 这应该不是HouseMD的问题, 而是实现没能很好的覆写toString方法, 而这个问题被HouseMD暴露出来了.

ferdiknight commented 12 years ago

嗯,找到问题了~谢谢你的帮助~ 是fastjson parseObject的时候传入了接口的class实列,反序列化的时候不会抛异常,但是之后调用的所有方法都会被fastjson拦截,然后invoke只去解析setter和getter方法,所以toString就会直接抛异常了。

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Class<?>[] parameterTypes = method.getParameterTypes();
        if (parameterTypes.length == 1) {
            Class<?> returnType = method.getReturnType();
            if (returnType != void.class) {
                throw new JSONException("illegal setter");
            }

            String name = null;
            JSONField annotation = method.getAnnotation(JSONField.class);
            if (annotation != null) {
                if (annotation.name().length() != 0) {
                    name = annotation.name();
                }
            }

            if (name == null) {
                name = method.getName();
                if (!name.startsWith("set")) {
                    throw new JSONException("illegal setter");
                }

                name = name.substring(3);
                if (name.length() == 0) {
                    throw new JSONException("illegal setter");
                }
                name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
            }

            map.put(name, args[0]);
            return null;
        }

        if (parameterTypes.length == 0) {
            Class<?> returnType = method.getReturnType();
            if (returnType == void.class) {
                throw new JSONException("illegal getter");
            }

            String name = null;
            JSONField annotation = method.getAnnotation(JSONField.class);
            if (annotation != null) {
                if (annotation.name().length() != 0) {
                    name = annotation.name();
                }
            }

            if (name == null) {
                name = method.getName();
                if (name.startsWith("get")) {
                    name = name.substring(3);
                    if (name.length() == 0) {
                        throw new JSONException("illegal getter");
                    }
                    name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
                } else if (name.startsWith("is")) {
                    name = name.substring(2);
                    if (name.length() == 0) {
                        throw new JSONException("illegal getter");
                    }
                    name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
                } else {
                    throw new JSONException("illegal getter");
                }
            }

            Object value = map.get(name);
            return TypeUtils.cast(value, method.getGenericReturnType(), ParserConfig.getGlobalInstance());
        }

        throw new UnsupportedOperationException(method.toGenericString());
    }