ReadyTalk / avian

[INACTIVE] Avian is a lightweight virtual machine and class library designed to provide a useful subset of Java's features, suitable for building self-contained applications.
https://readytalk.github.io/avian/
Other
1.22k stars 173 forks source link

Several methods missing in java.lang.Class #344

Closed bigfatbrowncat closed 10 years ago

bigfatbrowncat commented 10 years ago

We (me and @JustAMan) have tried using GSON (very popular Java JSON serializing/deserializing library) with Avian + Android classpath, and it turns out that Class misses several methods that are needed by GSON. Also note that Class.java is always taken from Avian classpath, so this issue is relevant for all Avian versions (i.e. both Avian's own classpath and Android classpath).

Namely:

Class.isAnonymousClass
Class.isLocalClass
Class.getGenericInterfaces

are missing or throwing UnsupportedOperationException.

We cannot progress further in finding what GSON needs except those three as we cannot stub getGenericInterfaces with something meaningful (stubbing it with empty list results in ArrayIndexOutOfBoundsException somewhere in the code path so GSON needs that method to provide correct results).

It would be wonderful if you could share your thoughts on where we could get the data needed for those methods if you cannot provide a quick fix yourself.

dicej commented 10 years ago

https://github.com/ReadyTalk/avian/pull/345

bigfatbrowncat commented 10 years ago

Thank you very much! Now I've proceeded to the next problem: there is no isSynthetic() method in the Field class. But we need it. Could you give a tip about how to implement it?

By the way, there is no Member interface in Avian (http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Member.html). Maybe we should create one?

bigfatbrowncat commented 10 years ago

So what about isSynthetic() and the Member interface?

dicej commented 10 years ago
public boolean isSynthetic() {
  return (vmField.flags & 0x1000) != 0;
}

And, yes, let's add Member if it's needed.

bigfatbrowncat commented 10 years ago

Cool. Thank you! By the way, where are flags values documented?

dicej commented 10 years ago

http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.1-200-E.1 http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.5-200-A.1 http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.6-200-A.1

bigfatbrowncat commented 10 years ago

I have an idea. As soon as these constants are returned by getModifiers() function (and are used in all Member descendants), maybe it would be good to declare them as protected static finals in Member class. This would help to avoid excessive magic numbering.

dicej commented 10 years ago

Sounds fine to me.

bigfatbrowncat commented 10 years ago

Finally I've made GSON working! I implemented getGenericSuperclass() and isSynthetic(). I've made a pool request https://github.com/ReadyTalk/avian/pull/350. And now it works. Look at this:

public class Message {
    public final long id;
    public final String userId;
    public final String text;

    public Message(long id, String userId, String text) {
        this.id = id;
        this.userId = userId;
        this.text = text;
    }
}

...

UUID user1Id = UUID.randomUUID();
UUID user2Id = UUID.randomUUID();

Message m1 = new Message(120, user1Id.toString(), "Hello from user1!");
Message m2 = new Message(121, user2Id.toString(), "Hello from user2!");

List<Message> msgs = new LinkedList<Message>();
msgs.add(m1);
msgs.add(m2);

GsonBuilder gb = new GsonBuilder();
Gson gg = gb.create();
String msgsAsJson = gg.toJson(msgs);

This code produces something like this:

[{"id":120,"userId":"7e89174e-b882-4c06-a19b-d4a0f2d736af","text":"Hello from user1!"},{"id":121,"userId":"721a8186-97fd-407c-9d02-23d916fe1ca6","text":"Hello from user2!"}]

I can not guarantee that GSON is 100% supported now, but it could serialize simple objects and object lists.

bigfatbrowncat commented 10 years ago

Oops... not everything yet. I have a problem with

java/lang/UnsatisfiedLinkError: java/lang/Class.getEnclosingClass()Ljava/lang/Class;
  at java/lang/Class.getEnclosingClass (native)

in Android classpath. Where is this method implemented?

dicej commented 10 years ago

https://github.com/ReadyTalk/avian/pull/351

bigfatbrowncat commented 10 years ago

Thank you! When are you going to merge it?

dscho commented 10 years ago

Finally I've made GSON working!

Congratulations!

dicej commented 10 years ago

@bigfatbrowncat, I'll let @joshuawarner32 merge it when he has a chance to look at it.

bigfatbrowncat commented 10 years ago

Thank you.

bigfatbrowncat commented 10 years ago

Ok, as pull request #351 is merged, I think, this bug should be closed. Thank you, guys.