ASM to parse .class against the rule defined in xml - java

I am using ASM bytecode reader to parse .class file present in the code.
But I want to get the particular string defined in the class which inturn will be mentioned inside the xml.
So how to use XML and parse the string present in .class. As I see there is ClassReader only takes .class as a parameter not the XML or any other format.
I am using something like this:
InputStream in=String.class.getResourceAsStream("/java/lang/String.class");
ClassReader classReader=new ClassReader(in);
classReader.accept(v, 0);
please tell me is there any way to parse .class against the rule defined in xml file?
Thanks in advance...
Yashu

As I understand it, you want to do the following: You are receiving a .class file and you then want to extract some sort of information from it which is specified in an XML file. If this is so: ASM does not need to know about what kind of information you are requiring. ASM will plainly read the class file. If you plainly want to know if some specific String is part of the class's constant pool, you could use a short cut for being notified of that: Override the ClassReader's readUTF8(int, char[]) method like this:
public MyClassReader extends ClassReader {
private final Set<String> constantPoolStrings = new HashSet<String>();
// Add constructors here
#Override
public String readUTF8(int index, char[] buf) {
String value = super.readUTF8(index, buf);
constantPoolStrings.add(value);
return value;
}
public boolean hasString(String value) {
// From the details in your comment, we will need to do a fuzzy search.
for(String poolString : constantPoolStrings) {
if(poolString.contains(value)) {
return true;
}
}
return false;
}
}
Of course you have to provide some logic that knows what String you are interested in: If you for example have an XML file that contains specific words you will need to parse this file and extract these words. You can than query the MyClassReader for these Strings.

Related

jUnit for file reader

I got a method that read from a txt file and populate a list with words that are exists in the file.
the method is calculate and return Most Repeated Word.
If I want to write a jUnit for that. how should I test the corectess of that method given the fact the file is changing frequentaly.
As #jaibalaji wrote, JuintTests should not depend on resources outside of the JVMs memory.
So the first step must be to make your code under test (cut) independent of the actual file.
I got a method that read from a txt file and populate a list with words that are exists in the file. the method is calculate and return Most Repeated Word.
In this sentences you mention 3 responsibilities:
reading a file
populating a list
find Most Repeated Word
You should split this method so that you ed up with smaller classes with the one responsibility each only.
class TextAnalyser{
private final WordListBulder wordListBulder; // converts String into List of words
private final WordCountAnalyser wordCountAnalyser;
public TextAnalyser(WordListBulder wordListBulder, WordCountAnalyser wordCountAnalyser){
this.wordListBulder = wordListBulder;
this.wordCountAnalyser = wordCountAnalyser;
}
public String findMostRepeatedWordIn(MyFileReader myFileReader){
String fileContent = myFileReader.readContent();
List<String> wordList = wordListBulder.crerateWordListFrom(fileContent);
return wordCountAnalyser.findMostRepeatedWordIn(wordList);
}
This code is too simple to fail and don't need to be UnitTested. Module- and/or Acceptance-Tests will show that this works.
Now the behavior to test is in the class WordCountAnalyser. And it has a simple t "fake" input which leads to a deterministic testable output.
The file should be a parameter of the method or an instance field of the class of this method.
In this way, you can unit test the method by providing a file which you master the data and you know how assert them.
For example with the parameter way :
public String findMostRepeatedWork(File file){
...
}
And so you could unit it easily :
#Test
public void findMostRepeatedWork(){
// fixture
File myTestFile = ...;
// action
new MyClassToTest.findMostRepeatedWork(myTestFile);
// assertion
...
}
Junit is not intended for any test that is taking resources(file, dB or network)

How to convert flat key-value file to a bean object dynamically?

I'd like to convert a flat file with many different keys to a java bean dto, as follows:
Flat file:
mykey=example
anotherkey=test
adress-street-1=downtown street
address-town-1=nyc
address-stree-2=some street
adrerss-town-2=los angeles
Target bean:
public class Content {
private String mykey;
private String anotherkey;
private List<Address> address;
}
public class Address {
private String street,
private String town;
}
Question: how could I achieve the mapping between the flat file and the target bean? Imagine a few hundred property keys. Some may occur multiple times, in whose cases they and with an index number, like address-town-1.
Content content = new Content();
while(true) {
String line = reader.readLine();
String key = line.split("=")[0];
String value = line.split("=")[1];
switch(key) {
case "mykey": content.setMykey(value);
case "anotherkey": content.setAnotherkey(value);
...
}
}
But I would have to code those mappings a few hundred times, which does not feel right.
Question: is there a better way, eg by using some kind of xml configuration/mapping file, and reflection?
BeanIO comes close to what I want to achieve. But it lacks the ability to just convert multiple different fields to the bean field name. And also it cannot group sets like the address-* example into a List.
Is there any known library or concept that I could use? Some framework that could do the formatting, using eg a xml configuration file?
Or would I have to write my own parser and use reflection to write the data to my java objects?

Is it possible to store pathparams as a list?

I have a Rest Service that I want to respond to requests with the following paths
1) /v1/config/type/service
2) /v1/config/type/service, service2
What I'd like is to be able to store the path param serviceName as a List where each element is delimited by a comma. For example, if someone types v1/config/foo/bar1,bar2,bar3 I'd like serviceName to be a List with 3 elements (bar1, bar2, bar3). Right now it just returns a list with 1 element that contains all three service strings. Is that even possible? Or is that something I'll simply have to parse. The code I have is shown below, it's pretty rough as I'm in the beginning stages of the project:
#ApplicationPath("/")
#Path("/v1/config")
public class ServiceRetriever extends Application {
#GET
#Produces(MediaType.TEXT_PLAIN)
public String getHelloWorld() {
return "Hello World";
}
#GET
#Path("{type}/{serviceName}")
#Produces("application/zip")
public Response getServices(#PathParam("type") String type, #PathParam("serviceName")List<String> serviceNames,
#QueryParam("with_config") boolean withConfig, #QueryParam("with_drive") boolean withDriver) throws IOException
{
//some random file i made to test that we can return a zip
File file = new File(System.getProperty("user.home")+"/dummy.zip");
System.out.println(serviceNames.size()); //returns 1
//we can change the zip file name to be whatever
return Response.ok(file).header("Content-Type","application/zip").
header("Content-Disposition", "attachment; filename="+file.getName()).build();
}
The problems is that you have to alter the deserialization process of that variable. Typically only query parameters are lists so this might not be compatible with some libraries.
You could:
Capture the parameter as a string and parse it internally via helper method (obvious)
Create your own annotation like #PathParamMutli and return Arrays.asList(parameter.split(","));. Ideally you should have access to the framework source code and branching privileges.
Use a query parameter instead

known API to write Bean/ResultSet into CSV file

I would like to export a Java Bean or ResultSet(JDBC) into a CSV file through Reflection mechanism.
I have seen this api :
http://opencsv.sourceforge.net/apidocs/au/com/bytecode/opencsv/bean/BeanToCsv.html
but it's not released yet.
Also, it will be fine if we can set some filters to avoid to map some precised fields.
Do you know a known API which owns these features ?
Unless there are some ready-made API:s I would use
Apache commons http://commons.apache.org/lang/api-2.4/org/apache/commons/lang/builder/ReflectionToStringBuilder.html to get a String representation of an JavaBean. By setting your own ToStringStyle it would be possible to create a CSV style String. There are many possible settings for styling of the String, including excluding fields and so on.
And then of course writing it to a file.
You can just write out to a csv file as you would to a normal .txt file by using an outputstream or so.
If you need more advanced excel like stuff I recommend using Apache POI. It has always done the job nice & clean for me.
Adding to Kennets answer:
I implemented two classes: One for the header (if needed) and one for the body (actual data)
HEADER
The header style class needs to extend ToStringStyle
Invoke toString with a single element, e.g. ReflectionToStringBuilder.toString(firstElement, headerStyle)
Constructor:
this.setUseClassName(false);
this.setUseIdentityHashCode(false);
this.setContentStart("");
this.setUseFieldNames(true);
this.setFieldNameValueSeparator("");
this.setContentEnd("\n");
Override Method:
#Override
public void append(StringBuffer buffer, String fieldName, Object value, Boolean fullDetail) {
super.append(buffer, fieldName, "", fullDetail);
}
BODY
The body class needs to extend RecursiveToStringStyle
Invoke toString with an array, e.g. ReflectionToStringBuilder.toString(array, bodyStyle)
Constructor:
this.setUseClassName(false);
this.setUseIdentityHashCode(false);
this.setContentStart("");
this.setUseFieldNames(false);
this.setContentEnd("");
this.setNullText("n.a.");
this.setArrayStart("");
this.setArrayEnd("");
this.setArraySeparator("\n");
Override Method:
#Override
public void append(StringBuffer buffer, String fieldName, Object value, Boolean fullDetail) {
String csvField = Optional.ofNullable(value)
.map(Objects::toString)
.map(this::escapeLineBreak)
.map(this::escapeDoubleQuote)
.map(this::escapeField)
.orElse(null);
super.append(buffer, fieldName, csvField, fullDetail);
}
Formatting Methods:
private String escapeDoubleQuote(final String field) {
return field.replace("\"", "\"\"");
}
private String escapeLineBreak(final String field) {
return field.replaceAll("\\R", " ");
}
private String escapeField(final String field) {
return "\"" + field + "\"";
}

Set default value in JAXB

I have an xml file as following and when the filePath2 is null or empty I want the value of that to be of filePath1's value. Is there a way in which I can achieve this through JAXB.
<file filePath1="C:/filePath">
<subFile name="Test">
<filePath2></filePath2>
</subFile>
<file/>
I don't want to hardcode the default value. If the value for filePath2 is null or blank("") I want to set the filePath1 attribute as the value of 'String filePath'. Is there a way to do it via a setter in JAXB?
Using plain Oracle JAXB I only see the possibility to implement that using an javax.xml.bind.Unmarshaller.Listener.
Implement that interface in your model class and perform the necessary checks in the afterUnmarshal(..) method.
There you can access the value of filePath1 and set (if necessary) it to filePath2.
Thanks for all your inputs, at the end I opted for a simpler solution; to update the setter where filePath2 is being called.
The JAXB part -
String filePath2;
#XmlElement(required = true)
public void setFilePath2(final String file) {
this.filePath2= file;
}
Where filePath is used -
if (filePath2 == null || filePath2.isEmpty()) {
setFilePath2(getFilePath1());
}
If you come across a bettr yet simple solution let me know.
If you can use annotations, than this should do the trick
...
private String foo;
#XmlElement(defaultValue="bar")
public String getFoo() {
return foo;
}
...

Categories