known API to write Bean/ResultSet into CSV file - java

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 + "\"";
}

Related

java create name of file with object sending a pattern

I am working with external configuration files, such as an application.yml in Springboot, the program copied files and renamed the files, but if I need another pattern the name of the files thengo to change in code.
Let's suppose the following code:
public class Pet {
private chain name;
private rope bread;
private chain size;
PrivateVar private chain;
Getters and Setters ....
}
And I make the name of the files with this code:
Pet pet = getPet();
String fileName = String.format ("% s_% s_% s_% s", pet.getName (), pet.getBread (), pet.getSize (), pet.getOtherVar ());
This is the problem, it is not dynamic.
In my configuration file, I think, I can write the pattern and send an object as input and have the patron organize the name.
String.format (pattern_from_the_file_config, pet);
Can I do this or is there any way to do this?
Consider using a method (Pet's in this example) to specify and return filename.
If it's still too hardcoded for you, maybe reflections may help.
Java Reflection API
But it's really not recommended, dangerous and should be used only if necessary. Think twice before you'll use it. By doing that, you are losing control of code correctness (for example if you made mistake by typing wrong class field/method name in your configuration file).
Why you just don't simply override the ToString() method?
According to your example:
#Override
public String toString() {
return String.format ("% s_% s_% s_% s", pet.getName (), pet.getBread (), pet.getSize (), pet.getOtherVar ());
}
this will change dynamically.
As Peteef mentioned such trick would require Java Reflection API usage. If you aware about potential problems, consider following code snippet:
//...
String fileName = getFileName(classNameFromConfigFile);
//...
String getFileName(String className) throws Exception {
Class<?> clazz = Class.forName(className);
StringBuilder nameBuilder = new StringBuilder();
String nameSeparator = "_";
for(Field field : clazz.getDeclaredFields()) {
nameBuilder.append(nameSeparator).append(field.getName());
}
return nameBuilder.toString();
}

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

Spark - save RDD to multiple files as output

I have a JavaRDD<Model>, which i need to write it as more than one file with different layout [one or two fields in the RDD will be different between different layout].
When i use saveAsTextFile() its calling the toString() method of Model, it means same layout will be written as output.
Currently what i am doing is iterate the RDD using map transformation method and return the different model with other layout, so i can use saveAsTextFile() action to write as different output file.
Just because of one or two fields are different , i need to iterate the entire RDD again and create new RDD then save it as output file.
For example:
Current RDD with fields:
RoleIndicator, Name, Age, Address, Department
Output File 1:
Name, Age, Address
Output File 2:
RoleIndicator, Name, Age, Department
Is there any optimal solution for this?
Regards,
Shankar
You want to use foreach, not collect.
You should define your function as an actual named class that extends VoidFunction. Create instance variables for both files, and add a close() method that closes the files. Your call() implementation will write whatever you need.
Remember to call close() on your function object after you're done.
It is possible with Pair RDD.
Pair RDD can be stored in multiple files in a single iteration by using Hadoop Custom output format.
rdd.saveAsHadoopFile(path, key.class, value.class,CustomTextOutputFormat.class, jobConf);
public class FileGroupingTextOutputFormat extends MultipleTextOutputFormat<Text, Text> {
#Override
protected Text generateActualKey(Text key, Text value) {
return new Text();
}
#Override
protected Text generateActualValue(Text key, Text value) {
return value;
}
// returns a dynamic file name based on each RDD element
#Override
protected String generateFileNameForKeyValue(Text key, Text value, String name) {
return value.getSomeField() + "-" + name;
}
}

ASM to parse .class against the rule defined in xml

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.

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