Get declared methods in order they appear in source code - java

The situation seems to be abnormal, but I was asked to build serializer that will parse an object into string by concatenating results of "get" methods. The values should appear in the same order as their "get" equivalent is declared in source code file.
So, for example, we have
Class testBean1{
public String getValue1(){
return "value1";
}
public String getValue2(){
return "value2";
}
}
The result should be:
"value1 - value2"
An not
"value2 - value1"
It can't be done with Class object according to the documentation. But I wonder if I can find this information in "*.class" file or is it lost? If such data exists, maybe, someone knows a ready to use tool for that purpose? If such information can't be found, please, suggest the most professional way of achieving the goal. I thought about adding some kind of custom annotations to the getters of the class that should be serialized.

If you want that you have to parse the source code, not the byte code.
There are a number of libraries that parse a source file into a node tree, my favorite is the javaparser (hosted at code.google.com), which, in a slightly modified version, is also used by spring roo.
On the usage page you can find some samples. Basically you will want to use a Visitor that listens for MethodDefinitions.

Although reflection does not anymore (as of java 7 I think) give you the methods in the order in which they appear in the source code, the class file appears to still (as of Java 8) contain the methods in the order in which they appear in the source code.
So, you can parse the class file looking for method names and then sort the methods based on the file offset in which each method was found.
If you want to do it in a less hacky way you can use Javassist, which will give you the line number of each declared method, so you can sort methods by line number.

I don't think the information is retained.
JAXB, for example, has #XmlType(propOrder="field1, field2") where you define the order of the fields when they are serialized to xml. You can implemenet something similar

Edit: This works only on concrete classes (the class to inspect has its own .class file). I changed the code below to reflect this. Until diving deeper into the ClassFileAnalyzer library to work with classes directly instead of reading them from a temporary file this limitation exists.
Following approach works for me:
Download and import following libarary ClassFileAnalyzer
Add the following two static methods (Attention! getClussDump() needs a little modification for writing out the class file to a temporary file: I removed my code here because it's very special at this point):
public static String getClassDump(Class<?> c) throws Exception {
String classFileName = c.getSimpleName() + ".class";
URL resource = c.getResource(classFileName);
if (resource == null) {
throw new RuntimeException("Works only for concreate classes!");
}
String absolutePath = ...; // write to temp file and get absolute path
ClassFile classFile = new ClassFile(absolutePath);
classFile.parse();
Info infos = new Info(classFile, absolutePath);
StringBuffer infoBuffer = infos.getInfos();
return infoBuffer.toString();
}
public static <S extends List<Method>> S sortMethodsBySourceOrder(Class<?> c, S methods) throws Exception {
String classDump = getClassDump(c);
int index = classDump.indexOf("constant_pool_count:");
final String dump = classDump.substring(index);
Collections.sort(methods, new Comparator<Method>() {
public int compare(Method o1, Method o2) {
Integer i1 = Integer.valueOf(dump.indexOf(" " + o1.getName() + lineSeparator));
Integer i2 = Integer.valueOf(dump.indexOf(" " + o2.getName() + lineSeparator));
return i1.compareTo(i2);
}});
return methods;
}
Now you can call the sortMethodsBySourceOrder with any List of methods (because sorting arrays is not very comfortable) and you will get the list back sorted.
It works by looking at the class dumps constant pool which in turn can be determined by the library.
Greetz,
GHad

Write your custom annotation to store ordering data, then use Method.getAnnotation(Class annotationClass)

Related

j2objc - exception when deserialize enum

I am having trouble deserializing objects that contain an enum. The object serializes without complaint, but I get an InvalidObjectException when I deserialize the object. The exception message says that there is "No enum constant com.mypackagname."
I have isolated and reproduced the problem by creating some test code based on the testSerialization() method in SerializationTest.java.
public class SerializationTest {
private static final String TEST_FILE_NAME = "serialization-test.bin";
public enum Gender { MALE, FEMALE }
public void testEnumSerialization() throws IOException, ClassNotFoundException {
Gender gender = Gender.MALE;
// Save the enum to a file.
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(TEST_FILE_NAME));
out.writeObject(gender);
out.close();
// Read back the enum.
ObjectInputStream in = new ObjectInputStream(new FileInputStream(TEST_FILE_NAME));
Gender gender2 = (Gender) in.readObject();
in.close();
}
}
I have discovered that if I add a string value to the enum initialization in the generated Objective C code the deserialization works fine. The resulting initialize method in Obj C looks like this:
+ (void)initialize {
if (self == [SerializationTest_Gender class]) {
JreEnum(SerializationTest_Gender, MALE) = new_SerializationTest_Gender_initWithNSString_withInt_(#"MALE", 0);
JreEnum(SerializationTest_Gender, FEMALE) = new_SerializationTest_Gender_initWithNSString_withInt_(#"FEMALE", 1);
J2OBJC_SET_INITIALIZED(SerializationTest_Gender)
}
}
Note that I added the #"MALE" and #"FEMALE", the default from the j2objc output is #"".
I have two questions. (1) Is this the correct way to enable a round trip serialization/deserialization of enums? (2) If so, is there a way to have j2objc automatically populate the string constants in the enum rather than coding them by hand?
Thanks for any help you can provide.
We probably broke this with a recent change eliminating redundant enum constant name strings. We had the name defined both in the enum's class initializer and in its metadata, plus we had an important request to stop making enum constants easily discovered in app binaries (apparently tech writers have been known to dump early access binaries and run strings on them to get scoops on any new features). Now the constant name is only in the metadata (no redundancy), and if an app builds with --strip-reflection, the enum has no metadata and the name becomes the enum class plus the constant's ordinal. However, serialization support was overlooked since Google apps use protocol buffers instead (faster and less version-sensitive).
Thanks for the excellent test case, which will make it easier to fix. Please file a bug if you want to be notified when this is fixed.

Getting qualified method name by the line number

This question is Java and Maven specific. Please note the additional constraints below as they are different from other questions.
I have several Maven (Java) projects to analyze. What I have is:
the source code
maven-compiled Jave code with binaries in target/ folder
The question is:
Given one source code file (.java) and a line number there, how can I get the fully qualified name of the method that spans over that line? If the line is not in a method then just output null. Acceptable languages to implement this are: Java, ruby, or python.
Could you please answer the question in one of the following two ways?
use the binary and extract qualified method name of that line. (This might involve weave in debug info, but that is fine.)
directly use the source file given, try to parse it and use the AST.
Using specific libraries (like BCEL) or any 3rd party ones (as long as they are well documented and usable) are OK, too.
Many many thanks for the huge help!
Unfortunately, your question is full of drawbacks:
You could, of corse, parse the input source (through an Javacc or ANTLR parser) until you reach the desired line. But it seems a waste of effort to parse the same source since you already have the .class files.
So, it seems better to analyze the .class file. But unfortunately, you have no gurantee that this is the class where your line spawns at, because there can be more than one class defined in the same source file.
Augh! That leads me to a kind of complicated solution:
I'll declare a class which will contain all the login:
public class SourceMethodsIndexer
{
private final SortedMap<Integer, List<Method>> indexOfMethodsByFirstLineNumber;
}
The constructor will be like this:
public SourceMethodsIndexer(File sourceFile)
... and should do these tasks:
1.Browse the class directory related to the target package.
File targetPackageDir=getTargetPackageDir(sourceFile);
File[] classFiles=targetPackageDir.listFiles(new FileFilter(){
public boolean accept(File dir, String name){
return name.endsWith(".class");
}
});
2.Use Apache BCEL to collect all the non public classes belonging to your input source file (you can invoke JavaClass.getSourceFileName() to filter classes), plus the public class corresponding to the name of your input source file.
Collection<JavaClass> targetClasses=getNonPublicClasses(classFiles, sourceFile.getName());
targetClasses.add(publicClass);
3.Collect then all the methods in each class.
Set<Method> targetMethods=new HashSet<Method>(1024);
for (JavaClass javaClass:targetClasses)
{
targetMethods.addAll(Arrays.asList(javaClass.getMethods()));
}
4.Now you can either search directly your line number, or index first the methods by line number to access them later more quickly: JavaClass.getMethods()[n].getLineNumberTable().getSourceLine(0) (take care that there could be repeated values).
this.indexOfMethodsByFirstLineNumber=new TreeMap<Integer, List<Method>>((int)(1.7d*methods.size()));
for (Method method: methods)
{
// Note: The -1 in this line stands to make the SortedMap work properly when searching for ranges.
int firstLine=getLineNumberTable().getSourceLine(0)-1;
List<Method> methodsInTheSameLine=indexOfMethodsByFirstLineNumber.get(firstLine);
if (methodsInTheSameLine==null)
{
methodsInTheSameLine=new ArrayList<Method>();
indexOfMethodsByFirstLineNumber.put(firstLine,methodsInTheSameLine);
}
methodsInTheSameLine.add(method);
}
5.Public a method to do the search:
public Method getMethodByLine(int lineNumber)
{
Set<Method> methodsInTheSameLine=this.indexOfMethodsByFirstLineNumber.headMap(lineNumber).lastKey();
if (methodsInTheSameLine.size()==0)
{
// There are no methods method in that line: Absurd.
}
else if (methodsInTheSameLine.size()>1)
{
// There are more than one method in that line. Hardly probable, but possible.
}
else
{
// There is one method in that line:
return methods.get(0);
}
}
There are a number of open source Maven plugins which analyse source code, and report on a per-method basis. A careful study of some of those may be your best bet.
Examples include Checkstyle, FindBugs, PMD, JDepend, JavaNCSS.
Also take a look at SonarQube.

Java Fluent API - better method?

Say I have an object that I've created to further simplify reading an XML document using the DOM parser. In order to "step into" a node or element, I'd like to use a single line to go from the start of the document to my target data, buried somewhere within the document, while bypassing the extra "fluff" of the DOM parser (such as doc.getElementsByTagName("data").item(0) when there is only one item inside the "data" element).
For the sake of this question, let's just assume there are no duplicate element tags and I know where I need to navigate to to get the data I need from the document, of which the data is a simple string. The idea is to set the simplified reader up so that it can be used for other data in other locations in the document, as well, without having to write new methods all the time. Below is some example code I've tried:
public class SimplifiedReader {
Document doc;
Element ele;
public SimplifiedReader(Document doc) {
this.doc = doc;
ele = doc.getDocumentElement();
}
public SimplifiedReader fromRoot() {
ele = doc.getDocumentElement();
return this;
}
public SimplifiedReader withEle(String elementName) {
ele = ele.getElementsByTagName(elementName).item(0);
return this;
}
public String getTheData(String elementName) {
return ele.getTextContent();
}
}
Example XML File:
<?xml version="1.0" encoding="UTF-8"?>
<fileData>
<subData>
<targetData>Hello World!</targetData>
<otherData>FooBar!</otherData>
</subData>
</fileData>
This results in me being able to navigate the XML file, and retrieve the Strings "Hello World!" and "FooBar!" using this code:
SimplifiedReader sr = new SimplifiedReader(doc);
String hwData = sr.withEle("fileData").withEle("subData").getTheData("targetData");
String fbData = sr.getTheData("otherData");
Or, if I had to go to another thread to get the data "FooBar!", I would just do:
String fbData = sr.fromRoot().withEle("fileData2").withEle("subData2").getTheData("otherData");
Is there a better/more correct way to do this? Edit: Note: This question is more about the method of returning an object from a method inside of it (return this;) in order to reduce the amount of code written to access specific data stored within a tree format and not so much about how to read an XML file. (I originally thought this was the Singleton Pattern until William corrected me... thank you William).
Thanks in advance for any help.
I don't see any trace of the Singleton pattern here. It mostly resembles the Builder pattern, but isn't it, either. It just implements a fluent API.
Your approach seems very nice and practical.
I would perhaps advise not using fromRoot() but instead constructing a new instance each time. The instance is quite lightweight since all the heavyweight stuff resides in the Document instance it wraps.
You could even go immutable all the way, returning a new instance from withEle(). This buys you many cool properties, like the freedom to share the object around, each code path being free to use it as a starting point to fetch something specific relative to it, share it across threads, etc. The underlying Document is mutable, but usually this doesn't create real-life problems when the code is all about reading.
Is there a better/more correct way to do this?
Yes, there are many better ways to extract values from XML.
One would be to use XPath, for example with XMLBeam.
import java.io.IOException;
import org.xmlbeam.XBProjector;
import org.xmlbeam.annotation.XBDocURL;
import org.xmlbeam.annotation.XBRead;
public class App {
public static void main(String[] args) throws IOException {
FileDate fileDate = new XBProjector().io().fromURLAnnotation(FileDate.class);
System.out.println(fileDate.getTargetDate());
// Hello World!
System.out.println(fileDate.getOtherDate());
// FooBar!
}
#XBDocURL("resource://filedate.xml")
public interface FileDate {
#XBRead("/fileData/subData/targetData")
String getTargetDate();
#XBRead("/fileData/subData/otherData")
String getOtherDate();
}
}

GWT - impossible to find working dir with Eclipse

I need to show on my panel the working dir.
I use String value = System.getProperty("user.dir"). Afterwards i put this string on label but I receive this message on console:
The method getProperty(String, String) in the type System is not applicable for the arguments (String).
I use eclipse.
Issue
I am guessing you have not gone through GWT 101 - You cannot blindly use JAVA CODE on client side.
Explanation
You can find the list of classes and methods supported for GWT from JAVA.
https://developers.google.com/web-toolkit/doc/latest/RefJreEmulation
For System only the following are supported.
err, out,
System(),
arraycopy(Object, int, Object, int, int),
currentTimeMillis(),
gc(),
identityHashCode(Object),
setErr(PrintStream),
setOut(PrintStream)
Solution
In your case Execute System.getProperty("user.dir") in your server side code and access it using RPC or any other server side gwt communication technique.
System.getProperty("key") is not supported,
but System.getProperty("key", "default") IS supported, though it will only return the default value as there is not system properties per se.
If you need the working directory during gwt compile, you need to use a custom linker or generator, grab the system property at build time, and emit it as a public resource file.
For linkers, you have to export an external file that gwt can download and get the compile-time data you want. For generators, you just inject the string you want into compiled source.
Here's a slideshow on linkers that is actually very interesting.
http://dl.google.com/googleio/2010/gwt-gwt-linkers.pdf
If you don't want to use a linker and an extra http request, you can use a generator as well, which is likely much easier (and faster):
interface BuildData {
String workingDirectory();
}
BuildData data = GWT.create(BuildData.class);
data.workingDirectory();
Then, you need to make a generator:
public class BuildDataGenerator extends IncrementalGenerator {
#Override
public RebindResult generateIncrementally(TreeLogger logger,
GeneratorContext context, String typeName){
//generator boilerplate
PrintWriter printWriter = context.tryCreate(logger, "com.foo", "BuildDataImpl");
if (printWriter == null){
logger.log(Type.TRACE, "Already generated");
return new RebindResult(RebindMode.USE_PARTIAL_CACHED,"com.foo.BuildDataImpl");
}
SourceFileComposerFactory composer =
new SourceFileComposerFactory("com.foo", "BuildDataImpl");
//must implement interface we are generating to avoid class cast exception
composer.addImplementedInterface("com.foo.BuildData");
SourceWriter sw = composer.createSourceWriter(printWriter);
//write the generated class; the class definition is done for you
sw.println("public String workingDirectory(){");
sw.println("return \""+System.getProperty("user.dir")+"\";");
sw.println("}");
return new RebindResult(RebindMode.USE_ALL_NEW_WITH_NO_CACHING
,"com.foo.BuildDataImpl");
}
}
Finally, you need to tell gwt to use your generator on your interface:
<generate-with class="dev.com.foo.BuildDataGenerator">
<when-type-assignable class="com.foo.BuildData" />
</generate-with>

Java, Get all classes available to a URLClassLoader that implement a specific interface

I am working on a command line app that loads user specified text translators at runtime (path to class files/jar provided via command line arg). Basically I am taking that argument and using it to create a URLClassLoader. Then I need to find all classes available to the URLClassloader that implement the Transable interface.
Right now I am only allowing this command line arg to be a directory with class files in it. Making the solution fairly simple (code below). But honestly I don't like the solution as it breaks down for jar files, directory of jar files, etc... Also, this obviously breaks down for any classes with a defined package, as loadClass needs the full name including the package. Anyone have a better method?
File d = new File(path);
if(d.isDirectory()) {
URL url = d.toURI().toURL();
ClassLoader cl = new URLClassLoader(new URL[]{url});
FilenameFilter filter = new FilenameFilter() {
#Override
public boolean accept(File dir, String name) {
return name.endsWith(".class");
}
};
for(File f : d.listFiles(filter)) {
String name = f.getName().substring(0, f.getName().indexOf("."));
String key = "";
if(name.endsWith("Translator")) {
key = name.substring(0, name.indexOf("Translator"));
}
else if(name.endsWith("translator")) {
key = name.substring(0, name.indexOf("translator"));
}
else
key = name;
Class c = cl.loadClass(name);
if(Transable.class.isAssignableFrom(c)) {
Transable t = (Transable)c.newInstance();
env.registerTranslator(key, t);
}
else {
System.out.println("[ClassLoader] "+c.getCanonicalName()+" will not be loaded. It is not a translator class");
}
}
}
else {
throw new Error("NOT IMPLEMENTED");
}
You may just have to brute force it if you continue down this road. To my knowledge the default class loader will not even load a class into the JVM unless it is referenced somehow. Which means, some of your classes will be basically invisible unless you know their fully qualified class name to load them.
You may want to reconsider your requirements. As it would be far easier to load a set of Translators that you have been given the class names for.
Instead of searching for implementors explicitly, you should uss Java's Service Provider Interface (SPI) and the ServiceLoader class (introduced in Java 6). SPI is a pretty much a standard way to do what you are describing in Java.
Please see the official Java tutorial on how to create a service provider and how to use it, at runtime, with ServiceLoader.
This may fit the bill. If not, you ought to be able to look through their source to get an idea of what will work for you. http://code.google.com/p/reflections/
In principle this can't work for arbitrary classloaders, as they may use any way imaginable to actually load the classes, and not have any "directory listening" function at all.
A classloader might even generate classes (i.e. the bytecode for the classes) on the fly whenever a loadClass comes, and imagine a TransableClassloader where each such automatically defined class would implement your interface - your program would never end.
That said, for an URLClassloader you can use getURLs(), and for the jar: and file: URL you can use the JarFile or File api to get the list of filenames (and thus Classnames) to try. As you have the root of your package hierarchy given in the URL, finding the right package name is not difficult, too.
(If you need more details, say it.)
Edit: For the package names, they correspond to the directory names inside of your hierarchy. So, when you have a base URL which corresponds to (say) dir/classes, and find a class-file named dir/classes/com/company/gui/SimpleTranslator.class, it corresponds to class com.company.gui.SimpleTranslator.
So, remove the base prefix and replace / by . (and cut of the .class). (In a JarFile you don't have to cut a prefix off.)
Actually, if you use a recursive method to traverse your File hierarchy, you can build up your package-name with the same method, simply by appending Strings (give them as a parameter to the next recursive Invocation):
public void searchClassesInDir(File dir, String packagePrefix) {
if(dir.isDirectory()) {
String prefix = packagePrefix + dir.getName() + ".";
for(File f : dir.listFiles()) {
searchClasses(f, prefix);
}
}
else {
String fileName = dir.getName();
if(! fileName.endsWith(".class"))
return;
String className = packagePrefix + fileName.substring(0, fileName.length()-".class".length());
// now do the rest of your processing
}
}
searchClasses(new File(url.toURI()), "");
Would this help?
Since Class c = cl.loadClass(name);
Class method getInterfaces() returns an array of classes
Check each class name for match to translator class name.

Categories