I am studying ASM, and I want to use ClassVisitor to print infomation of a class, now I do not know when visitOuterClass method will be called. Here is my code.
Simulator class
public class OuterClass {
class InnerClass {
class InnerA{
}
}
static class StaticNestedClass{
}
}
ClassVisitor implementation and test code
public class ASMMain {
public static class ParsingVisitor extends ClassVisitor {
public ParsingVisitor() {
super(Opcodes.ASM9);
}
public ParsingVisitor(ClassVisitor classVisitor) {
super(Opcodes.ASM9, classVisitor);
}
#Override
public void visitSource(String source, String debug) {
super.visitSource(source, debug);
System.out.println("visitSource===" + source + "===" + debug);
}
#Override
public ModuleVisitor visitModule(String name, int access, String version) {
System.out.println("visitModule===" + name + "===" + access + "===" + version);
return super.visitModule(name, access, version);
}
#Override
public void visitNestHost(String nestHost) {
super.visitNestHost(nestHost);
System.out.println("visitNestHost===" + nestHost);
}
#Override
public void visitOuterClass(String owner, String name, String descriptor) {
super.visitOuterClass(owner, name, descriptor);
System.out.println("visitOuterClass===" + owner + "===" + name + "===" + descriptor);
}
#Override
public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
System.out.println("visitAnnotation===" + descriptor + "===" + visible);
return super.visitAnnotation(descriptor, visible);
}
#Override
public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) {
System.out.println("visitTypeAnnotation===" + typeRef + "===" + typePath + "===" + descriptor + "===" + visible);
return super.visitTypeAnnotation(typeRef, typePath, descriptor, visible);
}
#Override
public void visitAttribute(Attribute attribute) {
super.visitAttribute(attribute);
System.out.println("visitAttribute===" + attribute);
}
#Override
public void visitNestMember(String nestMember) {
super.visitNestMember(nestMember);
System.out.println("visitNestMember===" + nestMember);
}
#Override
public void visitPermittedSubclass(String permittedSubclass) {
super.visitPermittedSubclass(permittedSubclass);
System.out.println("visitPermittedSubclass===" + permittedSubclass);
}
#Override
public void visitInnerClass(String name, String outerName, String innerName, int access) {
super.visitInnerClass(name, outerName, innerName, access);
System.out.println("visitInnerClass===" + name + "===" + outerName + "===" + innerName + "===" + access);
}
#Override
public RecordComponentVisitor visitRecordComponent(String name, String descriptor, String signature) {
System.out.println("visitRecordComponent===" + name + "===" + descriptor + "===" + signature);
return super.visitRecordComponent(name, descriptor, signature);
}
#Override
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
System.out.println("visitField===" + access + "===" + name + "===" + descriptor + "===" + signature + "===" + value);
return super.visitField(access, name, descriptor, signature, value);
}
#Override
public void visitEnd() {
super.visitEnd();
System.out.println("visitEnd===");
}
}
public static void main(String[] args) throws IOException {
String filePath = "src/main/java/cn/sensorsdata/asm/";
File file = new File(filePath + "OuterClass$InnerClass.class");
byte[] bytes = FileUtils.readFileToByteArray(file);
ClassReader classReader = new ClassReader(bytes);
classReader.accept(new ParsingVisitor(), 0);
}
}
The OuterClass$InnerClass is output by javac OuterClass.java command.
When i run the test code, the visitOuterClass is not called, I want to know why?
Any help will be appreciated.
The nesting relationships are reported through invocations of visitInnerClass. I suppose, you already noted that there were invocations of that method for the OuterClass—OuterClass$InnerClass relation, as well as for OuterClass$InnerClass—OuterClass$InnerClass$InnerA when parsing the OuterClass$InnerClass class.
The method visitOuterClass has a different purpose and a very misleading name. It’s for visiting the enclosing method of a local class.
So when you change the example to
public class OuterClass {
void someMethod(String s) {
class InnerClass {
}
}
static class StaticNestedClass{
}
}
and parse OuterClass$1InnerClass, you will get an invocation of visitOuterClass with the arguments OuterClass, someMethod, and (Ljava/lang/String;)V, completely identifying the enclosing method.
Related
I have two methods upsert into couchbase. Then I write two Junit tester with springboottest. After one Junit tester completed another test will throw this exception. How to resolve?
There are two upsert methods:I don't know which one methods is better?
public List<RawJsonDocument> upsert2(String generatorId, String idPrefix, List<String> contents)
{
List<RawJsonDocument> rjd = new ArrayList<RawJsonDocument>(contents.size());
Observable.from(contents).flatMap(new Func1<String,Observable<String>>(){
#Override
public Observable<String> call(String t)
{
return bucket.async().counter(generatorId, 1)
.map(jsonLongDocument -> {
String idStr = idPrefix + generatorId + jsonLongDocument.content();
String jsonStr = idStr + "=" + t;
return jsonStr;
});
}}).subscribe(new Action1<String>() {
#Override
public void call(String t)
{
String[] s = t.split("[=]");
LOGGER.debug("\n methord2 generatorId:" + s[0] + "\n content:" + s[1]);
bucket.async().upsert(RawJsonDocument.create(s[0],s[1]));
}});
return rjd;
}
public List<RawJsonDocument> upsert1(String generatorId, String idPrefix, List<String> contents)
{
if(contents == null)
{
return null;
}
List<RawJsonDocument> rjd = new ArrayList<RawJsonDocument>(contents.size());
Observable.from(contents).flatMap(new Func1<String,Observable<RawJsonDocument>>(){
#Override
public Observable<RawJsonDocument> call(String t)
{
return bucket.async().counter(generatorId, 1)
.map(jsonLongDocument -> {
String idStr = idPrefix + generatorId + jsonLongDocument.content();
LOGGER.debug("\n method3 generatorId:" + idStr + "\n content:" + t);
return RawJsonDocument.create(idStr,t);
});
}}).subscribe(new Action1<RawJsonDocument>() {
#Override
public void call(RawJsonDocument t)
{
rjd.add(bucket.async().upsert(t).toBlocking().single());
}});
return rjd;
}
This is my Junit Tester:
#Test
public void testIncrementIds3()
{
assertThat(generatorId.upsert2("counter", "idprefix", Arrays.asList("aabbccdd","ffddeeaa")).size(),is(2));
assertThat(generatorId.upsert1("counter", "idprefix", Arrays.asList("aabbccdd","ffddeeaa")).size(),is(2));
}
It so happens that I need to support in Java JSON data coming from external data sources. There is one common pattern. It's an array containing fixed number of elements of certain different types. We call it tuple. Here is my example of de-serialization for 3-element tuple with particular expected types of elements using FasterXML Jackson:
public class TupleTest {
public static void main(String[] args) throws Exception {
String person = "{\"name\":\"qqq\",\"age\":35,\"address\":\"nowhere\",\"phone\":\"(555)555-5555\",\"email\":\"super#server.com\"}";
String jsonText = "[[" + person + ",[" + person + "," + person + "],{\"index1\":" + person + ",\"index2\":" + person + "}]]";
ObjectMapper om = new ObjectMapper().registerModule(new TupleModule());
List<FixedTuple3> data = om.readValue(jsonText, new TypeReference<List<FixedTuple3>>() {});
System.out.println("Deserialization result: " + data);
System.out.println("Serialization result: " + om.writeValueAsString(data));
}
}
class Person {
public String name;
public Integer age;
public String address;
public String phone;
public String email;
#Override
public String toString() {
return "Person{name=" + name + ", age=" + age + ", address=" + address
+ ", phone=" + phone + ", email=" + email + "}";
}
}
class FixedTuple3 {
public Person e1;
public List<Person> e2;
public Map<String, Person> e3;
#Override
public String toString() {
return "Tuple[" + e1 + ", " + e2 + ", " + e3 + "]";
}
}
class TupleModule extends SimpleModule {
public TupleModule() {
super(TupleModule.class.getSimpleName(), new Version(1, 0, 0, null, null, null));
setSerializers(new SimpleSerializers() {
#Override
public JsonSerializer<?> findSerializer(SerializationConfig config,
JavaType type, BeanDescription beanDesc) {
if (isTuple(type.getRawClass()))
return new TupleSerializer();
return super.findSerializer(config, type, beanDesc);
}
});
setDeserializers(new SimpleDeserializers() {
#Override
public JsonDeserializer<?> findBeanDeserializer(JavaType type,
DeserializationConfig config, BeanDescription beanDesc) throws JsonMappingException {
Class<?> rawClass = type.getRawClass();
if (isTuple(rawClass))
return new TupleDeserializer(rawClass);
return super.findBeanDeserializer(type, config, beanDesc);
}
});
}
private boolean isTuple(Class<?> rawClass) {
return rawClass.equals(FixedTuple3.class);
}
public static class TupleSerializer extends JsonSerializer<Object> {
public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
try {
jgen.writeStartArray();
for (int i = 0; i < 3; i++) {
Field f = value.getClass().getField("e" + (i + 1));
Object res = f.get(value);
jgen.getCodec().writeValue(jgen, res);
}
jgen.writeEndArray();
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
}
public static class TupleDeserializer extends JsonDeserializer<Object> {
private Class<?> retClass;
public TupleDeserializer(Class<?> retClass) {
this.retClass = retClass;
}
public Object deserialize(JsonParser p, DeserializationContext ctx) throws IOException, JsonProcessingException {
try {
Object res = retClass.newInstance();
if (!p.isExpectedStartArrayToken()) {
throw new JsonMappingException("Tuple array is expected but found " + p.getCurrentToken());
}
JsonToken t = p.nextToken();
for (int i = 0; i < 3; i++) {
final Field f = res.getClass().getField("e" + (i + 1));
TypeReference<?> tr = new TypeReference<Object>() {
#Override
public Type getType() {
return f.getGenericType();
}
};
Object val = p.getCodec().readValue(p, tr);
f.set(res, val);
}
t = p.nextToken();
if (t != JsonToken.END_ARRAY)
throw new IOException("Unexpected ending token in tuple deserializer: " + t.name());
return res;
} catch (IOException ex) {
throw ex;
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
}
}
But this approach means I have to make new class every time I face new type configuration in tuple of certain size. So I wonder if there is any way to define deserializer dealing with generic typing. So that it will be enough to have one tuple class per tuple size. For instance my generic tuple of size 3 could be defined like:
class Tuple3 <T1, T2, T3> {
public T1 e1;
public T2 e2;
public T3 e3;
#Override
public String toString() {
return "Tuple[" + e1 + ", " + e2 + ", " + e3 + "]";
}
}
And usage of it would look like:
List<Tuple3<Person, List<Person>, Map<String, Person>>> data =
om.readValue(jsonText,
new TypeReference<List<Tuple3<Person, List<Person>, Map<String, Person>>>>() {});
Is it something doable or not?
Ok. So... there may be a simpler way to do "tuple"-style. You can actually annotate POJOs to be serialized as arrays:
#JsonFormat(shape=JsonFormat.Shape.ARRAY)
#JsonPropertyOrder({ "name", "age" }) // or use "alphabetic"
public class POJO {
public String name;
public int age;
}
and if so, they'll get written as arrays, read from arrays.
But if you do what to handle custom generic types, you probably need to get type parameters resolved. This can be done using TypeFactory, method findTypeParameters(...). While this may seem superfluous, it is needed for general case if you sub-type (if not, JavaType actually has accessors for direct type parameters).
Yes, you must use Reflection to get ALL FIELDS, not to get the known fields by name.
So I'm following the instructions for creating a Crosswalk extension on https://crosswalk-project.org/documentation/embedding_crosswalk/extensions.html. My question relates to extending the XWalkExtension class.
package org.crosswalkproject.sample;
import org.xwalk.core.XWalkExtension;
public class ExtensionEcho extends XWalkExtension {
private static String name = "echo";
private static String jsapi = "var echoListener = null;" +
"extension.setMessageListener(function(msg) {" +
" if (echoListener instanceof Function) {" +
" echoListener(msg);" + " };" + "});" +
"exports.echo = function (msg, callback) {" +
" echoListener = callback;" + " extension.postMessage(msg);" +
"};" + "exports.echoSync = function (msg) {" +
" return extension.internal.sendSyncMessage(msg);" + "};";
public ExtensionEcho() {
super(name, jsapi);
}
#Override
public void onMessage(int instanceID, String message) {
postMessage(instanceID, "From java: " + message);
}
#Override
public String onSyncMessage(int instanceID, String message) {
return "From java sync: " + message;
}
}
When extending the XWalkExtension class, how can you get the android application context? Hence, if I wanted to create a Toast message, I can pass in the context.
There isn't a publicly documented interface to get the Activity from XWalkExtension. You can modify the constructor to store a private reference to an Activity, then simply pass it in from where you instantiate the extension.
public class ExtensionEcho extends XWalkExtension {
private final Activity activity;
public ExtensionEcho(Activity activity) {
this.activity = activity;
}
...
}
I have a jtable that can be edite and then saved (updated) to a text file.
User select a line (that contains a book record) and request to borrow that book,
I use this method to update, But now when update, the old data is not deleted.
user_AllBooks uAllBooks = new user_AllBooks();
#Override
public void actionPerformed(ActionEvent event) {
if (event.getSource() == borrowButton) {
borrowInitialize(bTable.getSelectedRow());
}
public void borrowInitialize(int row) {
if (uAllBooks.getValueAt(row, 3).equals("Yes")) {
JOptionPane.showMessageDialog(null, "This Book Was Borrowed");
} else {
uAllBooks.setValueAt("Yes", row, 3);
uAllBooks.fireTableRowsUpdated(row, row);
uAllBooks.updateFiles(uAllBooks.bData);
}
}
...
}
public class user_AllBooks extends AbstractTableModel {
...
public void updateFiles(ArrayList<BookInformation> data) {
PrintWriter Bpw = null;
try {
Bpw = new PrintWriter(new FileWriter("AllBookRecords.txt" , true));
for (BookInformation bookinfo : data) {
String line = bookinfo.getBookID()
+ " " + bookinfo.getBookName()
+ " " + bookinfo.getBookDate()
+ " " + bookinfo.getBorrowStatus();
Bpw.println(line);
}
Bpw.close();
} catch (FileNotFoundException e1) {
} catch (IOException ioe) {
}
}
...
}
My BookInformation Class:
public class BookInformation {
private String BookName;
private String BookDate;
private String BookID;
private String BorrowStatus;
public String getBookName() {
return BookName;
}
public void setBookName(String book_name) {
this.BookName = book_name;
}
public String getBookDate() {
return BookDate;
}
public void setBookDate(String book_date) {
this.BookDate = book_date;
}
public String getBookID() {
return BookID;
}
public void setBookID(String Book_id) {
this.BookID = Book_id;
}
#Override
public String toString() {
return BookID + " " + BookName + " "
+ BookDate + " " + BorrowStatus + "\n";
}
public String getBorrowStatus() {
return BorrowStatus;
}
public void setBorrowStatus(String borrowStat) {
BorrowStatus = borrowStat;
}
}
Thanks.
Change this line
Bpw = new PrintWriter(new FileWriter("AllBookRecords.txt" , true));
to
Bpw = new PrintWriter(new FileWriter("AllBookRecords.txt" , false));
The second parameter (boolean) changes whether it should append the text file (add to the end of it) or just rewrite everything.
Source: Javadoc constructor summary for FileWriter:
FileWriter(String fileName, boolean append)
Constructs a FileWriter object given a file name with a boolean
indicating whether or not to append the data written.
When reading up on the play2 documentation I found this:
Because of the way Play 2.0 works, action code must be as fast as
possible (i.e. non blocking). So what should we return as result if we
are not yet able to compute it? The response should be a promise of a
result!
Wow! This of course made me interested in playakka and akka.
I'm currently building an autocomplete application that is integrating with elasticsearch,
so this would be a perfect fit!
Controller:
public class AutoComplete extends Controller {
#BodyParser.Of(value = BodyParser.Json.class)
public static Result complete(final String term) {
F.Promise<List<String>> list = Akka.future(new Callable<List<String>>() {
public List<String> call() throws Exception {
List<String> list = IndexService.find(term);
return list;
}
});
return async(list.map(new F.Function<List<String>, Result>() {
#Override
public Result apply(List<String> list) throws Throwable {
return ok(Json.toJson(list));
}
}));
}
Service:
public static List<String> find(final String term) {
IndexQuery < SearchWord > query = SearchWord.find.query();
query.setQuery("{\n" +
" \"bool\": {\n" +
" \"should\": [\n" +
" {\n" +
" \"text\": {\n" +
" \"search_word.ngrams\": {\n" +
" \"operator\": \"and\",\n" +
" \"query\": \""+term+"\"\n" +
" }\n" +
" }\n" +
" },\n" +
" {\n" +
" \"text\": {\n" +
" \"search_word.full\": {\n" +
" \"boost\": 1,\n" +
" \"query\": \""+term+"\"\n" +
" }\n" +
" }\n" +
" }\n" +
" ]\n" +
" }\n" +
"}");
IndexResults<SearchWord> indexResults = SearchWord.find.search(query);
List<String> list = new ArrayList<String>();
for(SearchWord word : indexResults.getResults()){
list.add(word.getWord());
}
return list;
}
}
SearchWord:
#IndexType(name = "search_word")
public class SearchWord extends Index {
// Find method static for request
public static Index.Finder<SearchWord> find = new Index.Finder<SearchWord>(SearchWord.class);
public enum WordType {
NAME,
STRONG_SEARCH_WORD,
WEAK_SEARCH_WORD,
BANNED
}
private String word;
private WordType wordType;
public SearchWord() {
}
public SearchWord(IndexWord indexWord) {
super.id = ""+indexWord.getId();
this.word = StringUtils.lowerCase(indexWord.getWord());
this.wordType = WordType.valueOf(indexWord.getType());
}
public String getId() {
return super.id;
}
public void setId(String id) {
super.id = id;
}
public String getWord() {
return word;
}
public void setWord(String word) {
this.word = word;
}
public WordType getWordType() {
return wordType;
}
public void setWordType(WordType wordType) {
this.wordType = wordType;
}
#Override
public Map toIndex() {
HashMap map = new HashMap();
map.put("id", super.id);
map.put("word", word);
map.put("word_type", wordType.toString());
return map;
}
#Override
public Indexable fromIndex(Map map) {
if (map == null) {
return this;
}
this.word = (String) map.get("word");
this.wordType = WordType.valueOf((String)map.get("word_type"));
return this;
}
}
The code works very well but I must say that I'm not that sure that I have implemented this correctly. I'm really struggling to understand the documentation.
So my questions are basically:
Have I implemented the Future and Promise correctly?
Would it be better to create a custom actor, and in that actor perform the index
search, like the example in the docs:
=====
return async(
Akka.asPromise(ask(myActor,"hello", 1000)).map(
new Function<Object,Result>() {
public Result apply(Object response) {
return ok(response.toString());
}
}
)
);
Maybe you have some great example that I have not found yet?
AFAIK, your code is totally ok.
I may be wrong, but I think that the second option is strictly equivalent to the first one, since the Akka.future() method is a wrapper around the Akka.promise() method.
From the Akka class source code of Play 2.0.4:
/**
* Executes a block of code asynchronously in the application Akka Actor system.
*/
public static <T> Promise<T> future(java.util.concurrent.Callable<T> callable) {
return asPromise(akka.dispatch.Futures.future(callable, system().dispatcher()));
}
Although you have correctly implemented the Promise and Future, i wouldn't consider this code to be "non-blocking"...
It seems that the blocking call is
List<String> list = IndexService.find(term);
and although this is now wrapped in a promise/future, it is still a blocking call...
If you want to be truly non-blocking (with all its benefits), you'll have to make your data access (queries) non-blocking...
Oh, and a non-blocking action method should return a Promise of a Result, not a Result...
This is how i should write your code:
#BodyParser.Of(value = BodyParser.Json.class)
public static F.Promise<Result> complete(final String term) {
scala.concurrent.Future<List<String>> listFuture = IndexService.find(term);
F.Promise<List<String>> listPromise = F.Promise.wrap(listFuture);
return listPromise.map(new F.Function<List<String>, Result>() {
#Override
public Result apply(List<String> list) throws Throwable {
return ok(Json.toJson(list));
}
});
}
Hope this helps!