is it possible to scan the android classpath for annotations? - java

I want to scan the classpath for certain annotations in Android.
I have only found one solution to this problem: http://mindtherobot.com/blog/737/android-hacks-scan-android-classpath/
And as the author writes this solution works, but has several limitations. Are there any future-proof ways of doing this in android? Any libraries providing this functionality?

This works for me using android 3.0
public static <T extends Annotation> List<Class> getClassesAnnotatedWith(Class<T> theAnnotation){
// In theory, the class loader is not required to be a PathClassLoader
PathClassLoader classLoader = (PathClassLoader) Thread.currentThread().getContextClassLoader();
Field field = null;
ArrayList<Class> candidates = new ArrayList<Class>();
try {
field = PathClassLoader.class.getDeclaredField("mDexs");
field.setAccessible(true);
} catch (Exception e) {
// nobody promised that this field will always be there
Log.e(TAG, "Failed to get mDexs field", e);
}
DexFile[] dexFile = null;
try {
dexFile = (DexFile[]) field.get(classLoader);
} catch (Exception e) {
Log.e(TAG, "Failed to get DexFile", e);
}
for (DexFile dex : dexFile) {
Enumeration<String> entries = dex.entries();
while (entries.hasMoreElements()) {
// Each entry is a class name, like "foo.bar.MyClass"
String entry = entries.nextElement();
// Load the class
Class<?> entryClass = dex.loadClass(entry, classLoader);
if (entryClass != null && entryClass.getAnnotation(theAnnotation) != null) {
Log.d(TAG, "Found: " + entryClass.getName());
candidates.add(entryClass);
}
}
}
return candidates;
}
I also created one to determin if a class was derived from X
public static List<Class> getClassesSuperclassedOf(Class theClass){
// In theory, the class loader is not required to be a PathClassLoader
PathClassLoader classLoader = (PathClassLoader) Thread.currentThread().getContextClassLoader();
Field field = null;
ArrayList<Class> candidates = new ArrayList<Class>();
try {
field = PathClassLoader.class.getDeclaredField("mDexs");
field.setAccessible(true);
} catch (Exception e) {
// nobody promised that this field will always be there
Log.e(TAG, "Failed to get mDexs field", e);
}
DexFile[] dexFile = null;
try {
dexFile = (DexFile[]) field.get(classLoader);
} catch (Exception e) {
Log.e(TAG, "Failed to get DexFile", e);
}
for (DexFile dex : dexFile) {
Enumeration<String> entries = dex.entries();
while (entries.hasMoreElements()) {
// Each entry is a class name, like "foo.bar.MyClass"
String entry = entries.nextElement();
// Load the class
Class<?> entryClass = dex.loadClass(entry, classLoader);
if (entryClass != null && entryClass.getSuperclass() == theClass) {
Log.d(TAG, "Found: " + entryClass.getName());
candidates.add(entryClass);
}
}
}
return candidates;
}
enjoy - B

Related

Cheking uniqueness of key values in java properties files

I want to load a certain number of properties files into the same java.util.Properties object. I achieve this correctly with the following code:
public class GloalPropReader {
public static final Properties DISPATCHER = new Properties();
public static final Properties GLOBAL_PROP = new Properties();
public GloalPropReader() {
try (InputStream input = GloalPropReader.class.getClassLoader().getResourceAsStream("dispatcher.properties")) {
DISPATCHER.load(input);
} catch (IOException ex) {
throw new RuntimeException("Can't access dispatcher information");
}
for (Object nth : DISPATCHER.keySet()) {
String nthKey = (String) nth;
String nthPathToOtherProps = (String) DISPATCHER.get(nthKey);
Path p = Paths.get(nthPathToOtherProps);
try (InputStream input = new FileInputStream(p.toFile())) {
GLOBAL_PROP.load(input);
} catch (IOException ex) {
throw new RuntimeException("Can't access " + nthPathToOtherProps + " information");
}
}
}
}
And having this properties files:
dispatcher.properties
path_to_prop_1=C:/Users/U/Desktop/k.properties
path_to_prop_2=C:/Users/U/Desktop/y.properties
k.properties
prop1=BLABLA
y.properties
prop2=BLEBLE
But what i would like to achieve is to throw a RuntimeException if 2 properties file have the same key inside. For instance, i would like this class to throw an exception if k.properties and y.properties were so:
k.properties
prop1=BLABLA
y.properties
prop1=BLEBLE
EDIT
It's the same as this post Loading multiple properties files but i don't want the overriding logic when 2 keys are equal
public static class GloalPropReader {
private final Properties K_PROPERTIES = new Properties();
private final Properties Y_PROPERTIES = new Properties();
public GloalPropReader() {
loadProperties("k.properties", K_PROPERTIES);
loadProperties("y.properties", Y_PROPERTIES);
Set intersection = new HashSet(K_PROPERTIES.keySet());
intersection.retainAll(Y_PROPERTIES.keySet());
if (!intersection.isEmpty()) {
throw new IllegalStateException("Property intersection detected " + intersection);
}
}
private void loadProperties(String name, Properties y_properties) {
try (InputStream input = GloalPropReader.class.getClassLoader().getResourceAsStream(name)) {
y_properties.load(input);
} catch (IOException ex) {
throw new RuntimeException("Can't access dispatcher information");
}
}
}

DCM4CHE, Network operations,Handling a C-Move call

Hi I'm trying to make a PACS server using Java. dcm4che appears to be quite popular. But I'm unable to find any good examples about it.
As a starting point I inspected dcmqrscp and it successfully stores a DICOM image. But I cannot manage to handle a C-MOVE call. Here's my CMove handler. It finds requested the DICOM file adds a URL and other stuff, it doesn't throw any exception yet client doesn't receive any files.
private final class CMoveSCPImpl extends BasicCMoveSCP {
private final String[] qrLevels;
private final QueryRetrieveLevel rootLevel;
public CMoveSCPImpl(String sopClass, String... qrLevels) {
super(sopClass);
this.qrLevels = qrLevels;
this.rootLevel = QueryRetrieveLevel.valueOf(qrLevels[0]);
}
#Override
protected RetrieveTask calculateMatches(Association as, PresentationContext pc, final Attributes rq, Attributes keys) throws DicomServiceException {
QueryRetrieveLevel level = QueryRetrieveLevel.valueOf(keys, qrLevels);
try {
level.validateRetrieveKeys(keys, rootLevel, relational(as, rq));
} catch (Exception e) {
e.printStackTrace();
}
String moveDest = rq.getString(Tag.MoveDestination);
final Connection remote = new Connection("reciverAE",as.getSocket().getInetAddress().getHostAddress(), 11113);
if (remote == null)
throw new DicomServiceException(Status.MoveDestinationUnknown, "Move Destination: " + moveDest + " unknown");
List<T> matches = DcmQRSCP.this.calculateMatches(keys);
if (matches.isEmpty())
return null;
AAssociateRQ aarq;
Association storeas = null;
try {
aarq = makeAAssociateRQ(as.getLocalAET(), moveDest, matches);
storeas = openStoreAssociation(as, remote, aarq);
} catch (Exception e) {
e.printStackTrace();
}
BasicRetrieveTask<T> retrieveTask = null;
retrieveTask = new BasicRetrieveTask<T>(Dimse.C_MOVE_RQ, as, pc, rq, matches, storeas, new BasicCStoreSCU<T>());
retrieveTask.setSendPendingRSPInterval(getSendPendingCMoveInterval());
return retrieveTask;
}
private Association openStoreAssociation(Association as, Connection remote, AAssociateRQ aarq)
throws DicomServiceException {
try {
return as.getApplicationEntity().connect(as.getConnection(),
remote, aarq);
} catch (Exception e) {
throw new DicomServiceException(
Status.UnableToPerformSubOperations, e);
}
}
private AAssociateRQ makeAAssociateRQ(String callingAET,
String calledAET, List<T> matches) {
AAssociateRQ aarq = new AAssociateRQ();
aarq.setCalledAET(calledAET);
aarq.setCallingAET(callingAET);
for (InstanceLocator match : matches) {
if (aarq.addPresentationContextFor(match.cuid, match.tsuid)) {
if (!UID.ExplicitVRLittleEndian.equals(match.tsuid))
aarq.addPresentationContextFor(match.cuid,
UID.ExplicitVRLittleEndian);
if (!UID.ImplicitVRLittleEndian.equals(match.tsuid))
aarq.addPresentationContextFor(match.cuid,
UID.ImplicitVRLittleEndian);
}
}
return aarq;
}
private boolean relational(Association as, Attributes rq) {
String cuid = rq.getString(Tag.AffectedSOPClassUID);
ExtendedNegotiation extNeg = as.getAAssociateAC().getExtNegotiationFor(cuid);
return QueryOption.toOptions(extNeg).contains(
QueryOption.RELATIONAL);
}
}
I added the code below to send a DICOM file as a response:
String cuid = rq.getString(Tag.AffectedSOPClassUID);
String iuid = rq.getString(Tag.AffectedSOPInstanceUID);
String tsuid = pc.getTransferSyntax();
try {
DcmQRSCP.this.as=as;
File f = new File("D:\\dcmqrscpTestDCMDir\\1.2.840.113619.2.30.1.1762295590.1623.978668949.886\\1.2.840.113619.2.30.1.1762295590.1623.978668949.887\\1.2.840.113619.2.30.1.1762295590.1623.978668949.888");
FileInputStream in = new FileInputStream(f);
InputStreamDataWriter data = new InputStreamDataWriter(in);
// !1! as.cmove(cuid,1,keys,tsuid,"STORESCU");
as.cstore(cuid,iuid,1,data,tsuid,rspHandlerFactory.createDimseRSPHandler(f));
} catch (Exception e) {
e.printStackTrace();
}
Throws this exception
org.dcm4che3.net.NoRoleSelectionException: No Role Selection for SOP Class 1.2.840.10008.5.1.4.1.2.2.2 - Study Root Query/Retrieve Information Model - MOVE as SCU negotiated
You should add a role to the application instance like:
applicationEntity.addTransferCapability(
new TransferCapability(null, "*", TransferCapability.Role.SCP, "*"));

Loading classes from a set of files

I have a task to check a set of conditions for unknown set of classes from classpath. I want to scan it for classes, load each of them and perform my checks. Now I have a set of urls to class files and I try to use URLClassLoader. But to load a class I need to specify a fully qualified class name, but I don't have them (I have only file path). I don't think that building class name from class file path is relieble, is it a better way to do it?
Thanks!
I'd just parse the beginning of the class file, looking for "package" keyword and first occurrence of "class" keyword. Then, when you combine those two (packageName + "." + className), it should result in a proper class name.
I started a project once to automatically test classes found on the class path for run time exceptions, by calling constructors and methods reflectively with dodgy arguments like null, 0, 1, -1, "" etc.
That project has a class called Finder wich does roughly what you need:
static List<Class<?>> findClassesForPackage(String packagename, Report report) throws ClassNotFoundException {
// 'classes' will hold a list of directories matching the package name.
// There may be more than one if a package is split over multiple
// jars/paths
List<Class<?>> classes = new ArrayList<Class<?>>();
List<File> directories = new ArrayList<File>();
try {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
throw new ClassNotFoundException("Can't get class loader.");
}
// Ask for all resources for the path
String path = packagename.replace('.', '/');
Enumeration<URL> resources = classLoader.getResources(path);
while (resources.hasMoreElements()) {
URL res = resources.nextElement();
if (res.getProtocol().equalsIgnoreCase("jar")) {
JarURLConnection conn = (JarURLConnection) res.openConnection();
JarFile jar = conn.getJarFile();
for (JarEntry entry : Collections.list(jar.entries())) {
if (entry.getName().startsWith(path) && entry.getName().endsWith(".class")
&& !entry.getName().contains("$")) {
String className = entry.getName().replace("/", ".").substring(0,
entry.getName().length() - 6);
LOG.debug("Adding JAR className " + className);
try {
Class<?> clazz = Class.forName(className);
classes.add(clazz);
report.addClass(className);
} catch (Throwable throwable) {
ParamSet params = new ParamSet();
params.addParamValue(new ParamValue(className, "fully qualified classname"));
report.addError(className, new Error("Class.forName()", params, throwable));
}
}
}
} else
directories.add(new File(URLDecoder.decode(res.getPath(), "UTF-8")));
}
} catch (NullPointerException e) {
throw new ClassNotFoundException(String.format("%s does not appear to be a valid package", packagename), e);
} catch (UnsupportedEncodingException e) {
throw new ClassNotFoundException(String.format("%s does not appear to be a valid package", packagename), e);
} catch (IOException e) {
throw new ClassNotFoundException(String.format("Could not get all resources for %s", packagename), e);
}
List<String> subPackages = new ArrayList<String>();
// For every directory identified capture all the .class files
for (File directory : directories) {
if (directory.exists()) {
// Get the list of the files contained in the package
File[] files = directory.listFiles();
for (File file : files) {
// add .class files to results
String fileName = file.getName();
if (file.isFile() && fileName.endsWith(".class")) {
// removes the .class extension
String className = packagename + '.' + fileName.substring(0, fileName.length() - 6);
LOG.debug("Adding FILE className " + className);
try {
Class<?> clazz = Class.forName(className);
classes.add(clazz);
report.addClass(className);
} catch (Throwable throwable) {
ParamSet params = new ParamSet();
params.addParamValue(new ParamValue(className, "fully qualified classname"));
report.addError(className, new Error("Class.forName()", params, throwable));
}
}
// keep track of subdirectories
if (file.isDirectory()) {
subPackages.add(packagename + "." + fileName);
}
}
} else {
throw new ClassNotFoundException(String.format("%s (%s) does not appear to be a valid package",
packagename, directory.getPath()));
}
}
// check all potential subpackages
for (String subPackage : subPackages) {
classes.addAll(findClassesForPackage(subPackage, report));
}
return classes;
}
You probably have to strip some code that does reporting etc.

How to programmatically read a Java interface?

I'd like to implement a method that returns the field(s) from an interface that define a specified (int) value. I don't have source to the interface.
So, the signature could be something like this:
public ArrayList<String> getFieldnames(Object src, int targetValue);
And I'm assuming internally it could find the declared fields and test each against the value, returning the list.
ArrayList<String> s = new ArrayList<String>();
if( src!= null )
{
Field[] flist = src.getClass().getDeclaredFields();
for (Field f : flist )
if( f.getType() == int.class )
try {
if( f.getInt(null) == targetValue) {
s.add(f.getName());
break;
}
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
}
}
return s;
Unfortunately, this implementation is incorrect - it's as if there are no fields at all when called with the interface itself. If I pass an object that implements the interface, the list of possible fields will be too wide to be of use.
Thanks for any help!
public ArrayList<String> getFieldnames(Object src, int targetValue) {
final Class<?> myInterfaceClass = MyInterface.class;
ArrayList<String> fieldNames = new ArrayList<>();
if (src != null) {
for (Class<?> currentClass = src.getClass(); currentClass != null; currentClass = currentClass.getSuperclass()) {
Class<?> [] interfaces = currentClass.getInterfaces();
if (Arrays.asList(interfaces).contains(myInterfaceClass)) {
for (Field field : currentClass.getDeclaredFields()) {
if (field.getType().equals(int.class)) {
try {
int value = field.getInt(null);
if (value == targetValue) {
fieldNames.add(field.getName());
}
} catch (IllegalAccessException ex) {
// Do nothing. Always comment empty blocks.
}
}
}
}
}
}
return fieldNames;
}
This
src.getClass()
returns src class not interface. Consider this
interface I {
}
class A implements I {
}
new A().getClass() -- returns A.class
Although I would rather have passed in an object, I suppose changing the signature to a string value and passing in the FQIN gets the job done just as well.
Thanks to <this question> for the idea (and Google for directing me there).
Solution:
public ArrayList<String> getFieldnamesByValue(Class<?>x, int targetValue)
{
ArrayList<String> s = new ArrayList<String>();
if( x != null )
{
Field[] flist = x.getDeclaredFields();
for (Field f : flist )
if( f.getType() == int.class )
try {
if( f.getInt(null) == targetValue) {
s.add(f.getName());
break;
}
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
}
}
return s;
}

How to serialize object to CSV file?

I want to write a Object into CSV file.
For XML we have XStream like this
So if i want to convert object to CSV do we have any such library ?
EDIT:
I want to pass my list of Bean to a method which should write all the fields of bean to CSV.
First, serialization is writing the object to a file 'as it is'. AFAIK, you cannot choose file formats and all. The serialized object (in a file) has its own 'file format'
If you want to write the contents of an object (or a list of objects) to a CSV file, you can do it yourself, it should not be complex.
Looks like Java CSV Library can do this, but I have not tried this myself.
EDIT: See following sample. This is by no way foolproof, but you can build on this.
//European countries use ";" as
//CSV separator because "," is their digit separator
private static final String CSV_SEPARATOR = ",";
private static void writeToCSV(ArrayList<Product> productList)
{
try
{
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("products.csv"), "UTF-8"));
for (Product product : productList)
{
StringBuffer oneLine = new StringBuffer();
oneLine.append(product.getId() <=0 ? "" : product.getId());
oneLine.append(CSV_SEPARATOR);
oneLine.append(product.getName().trim().length() == 0? "" : product.getName());
oneLine.append(CSV_SEPARATOR);
oneLine.append(product.getCostPrice() < 0 ? "" : product.getCostPrice());
oneLine.append(CSV_SEPARATOR);
oneLine.append(product.isVatApplicable() ? "Yes" : "No");
bw.write(oneLine.toString());
bw.newLine();
}
bw.flush();
bw.close();
}
catch (UnsupportedEncodingException e) {}
catch (FileNotFoundException e){}
catch (IOException e){}
}
This is product (getters and setters hidden for readability):
class Product
{
private long id;
private String name;
private double costPrice;
private boolean vatApplicable;
}
And this is how I tested:
public static void main(String[] args)
{
ArrayList<Product> productList = new ArrayList<Product>();
productList.add(new Product(1, "Pen", 2.00, false));
productList.add(new Product(2, "TV", 300, true));
productList.add(new Product(3, "iPhone", 500, true));
writeToCSV(productList);
}
Hope this helps.
Cheers.
For easy CSV access, there is a library called OpenCSV. It really ease access to CSV file content.
EDIT
According to your update, I consider all previous replies as incorrect (due to their low-levelness). You can then go a completely diffferent way, the hibernate way, in fact !
By using the CsvJdbc driver, you can load your CSV files as JDBC data source, and then directly map your beans to this datasource.
I would have talked to you about CSVObjects, but as the site seems broken, I fear the lib is unavailable nowadays.
Two options I just ran into:
http://sojo.sourceforge.net/
http://supercsv.sourceforge.net/
It would be interesting to have a csv serializer as it would take up the minimal space compared to other serializing method.
The closest support for java object to csv is stringutils provided by spring utils project
arrayToCommaDelimitedString(Object[] arr) but it is far from being a serializer.
Here is a simple utility which uses reflection to serialize value objects
public class CSVWriter
{
private static String produceCsvData(Object[] data) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException
{
if(data.length==0)
{
return "";
}
Class classType = data[0].getClass();
StringBuilder builder = new StringBuilder();
Method[] methods = classType.getDeclaredMethods();
for(Method m : methods)
{
if(m.getParameterTypes().length==0)
{
if(m.getName().startsWith("get"))
{
builder.append(m.getName().substring(3)).append(',');
}
else if(m.getName().startsWith("is"))
{
builder.append(m.getName().substring(2)).append(',');
}
}
}
builder.deleteCharAt(builder.length()-1);
builder.append('\n');
for(Object d : data)
{
for(Method m : methods)
{
if(m.getParameterTypes().length==0)
{
if(m.getName().startsWith("get") || m.getName().startsWith("is"))
{
System.out.println(m.invoke(d).toString());
builder.append(m.invoke(d).toString()).append(',');
}
}
}
builder.append('\n');
}
builder.deleteCharAt(builder.length()-1);
return builder.toString();
}
public static boolean generateCSV(File csvFileName,Object[] data)
{
FileWriter fw = null;
try
{
fw = new FileWriter(csvFileName);
if(!csvFileName.exists())
csvFileName.createNewFile();
fw.write(produceCsvData(data));
fw.flush();
}
catch(Exception e)
{
System.out.println("Error while generating csv from data. Error message : " + e.getMessage());
e.printStackTrace();
return false;
}
finally
{
if(fw!=null)
{
try
{
fw.close();
}
catch(Exception e)
{
}
fw=null;
}
}
return true;
}
}
Here is an example value object
public class Product {
private String name;
private double price;
private int identifier;
private boolean isVatApplicable;
public Product(String name, double price, int identifier,
boolean isVatApplicable) {
super();
this.name = name;
this.price = price;
this.identifier = identifier;
this.isVatApplicable = isVatApplicable;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(long price) {
this.price = price;
}
public int getIdentifier() {
return identifier;
}
public void setIdentifier(int identifier) {
this.identifier = identifier;
}
public boolean isVatApplicable() {
return isVatApplicable;
}
public void setVatApplicable(boolean isVatApplicable) {
this.isVatApplicable = isVatApplicable;
}
}
and the code to run the util
public class TestCSV
{
public static void main(String... a)
{
Product[] list = new Product[5];
list[0] = new Product("dvd", 24.99, 967, true);
list[1] = new Product("pen", 4.99, 162, false);
list[2] = new Product("ipad", 624.99, 234, true);
list[3] = new Product("crayons", 4.99,127, false);
list[4] = new Product("laptop", 1444.99, 997, true);
CSVWriter.generateCSV(new File("C:\\products.csv"),list);
}
}
Output:
Name VatApplicable Price Identifier
dvd true 24.99 967
pen false 4.99 162
ipad true 624.99 234
crayons false 4.99 127
laptop true 1444.99 997
I wrote a simple class that uses OpenCSV and has two static public methods.
static public File toCSVFile(Object object, String path, String name) {
File pathFile = new File(path);
pathFile.mkdirs();
File returnFile = new File(path + name);
try {
CSVWriter writer = new CSVWriter(new FileWriter(returnFile));
writer.writeNext(new String[]{"Member Name in Code", "Stored Value", "Type of Value"});
for (Field field : object.getClass().getDeclaredFields()) {
writer.writeNext(new String[]{field.getName(), field.get(object).toString(), field.getType().getName()});
}
writer.flush();
writer.close();
return returnFile;
} catch (IOException e) {
Log.e("EasyStorage", "Easy Storage toCSVFile failed.", e);
return null;
} catch (IllegalAccessException e) {
Log.e("EasyStorage", "Easy Storage toCSVFile failed.", e);
return null;
}
}
static public void fromCSVFile(Object object, File file) {
try {
CSVReader reader = new CSVReader(new FileReader(file));
String[] nextLine = reader.readNext(); // Ignore the first line.
while ((nextLine = reader.readNext()) != null) {
if (nextLine.length >= 2) {
try {
Field field = object.getClass().getDeclaredField(nextLine[0]);
Class<?> rClass = field.getType();
if (rClass == String.class) {
field.set(object, nextLine[1]);
} else if (rClass == int.class) {
field.set(object, Integer.parseInt(nextLine[1]));
} else if (rClass == boolean.class) {
field.set(object, Boolean.parseBoolean(nextLine[1]));
} else if (rClass == float.class) {
field.set(object, Float.parseFloat(nextLine[1]));
} else if (rClass == long.class) {
field.set(object, Long.parseLong(nextLine[1]));
} else if (rClass == short.class) {
field.set(object, Short.parseShort(nextLine[1]));
} else if (rClass == double.class) {
field.set(object, Double.parseDouble(nextLine[1]));
} else if (rClass == byte.class) {
field.set(object, Byte.parseByte(nextLine[1]));
} else if (rClass == char.class) {
field.set(object, nextLine[1].charAt(0));
} else {
Log.e("EasyStorage", "Easy Storage doesn't yet support extracting " + rClass.getSimpleName() + " from CSV files.");
}
} catch (NoSuchFieldException e) {
Log.e("EasyStorage", "Easy Storage fromCSVFile failed.", e);
} catch (IllegalAccessException e) {
Log.e("EasyStorage", "Easy Storage fromCSVFile failed.", e);
}
} // Close if (nextLine.length >= 2)
} // Close while ((nextLine = reader.readNext()) != null)
} catch (FileNotFoundException e) {
Log.e("EasyStorage", "Easy Storage fromCSVFile failed.", e);
} catch (IOException e) {
Log.e("EasyStorage", "Easy Storage fromCSVFile failed.", e);
} catch (IllegalArgumentException e) {
Log.e("EasyStorage", "Easy Storage fromCSVFile failed.", e);
}
}
I think with some simple recursion these methods could be modified to handle any Java object, but for me this was adequate.
Though its very late reply, I have faced this problem of exporting java entites to CSV, EXCEL etc in various projects, Where we need to provide export feature on UI.
I have created my own light weight framework. It works with any Java Beans, You just need to add annotations on fields you want to export to CSV, Excel etc.
Link: https://github.com/abhisoni96/dev-tools
Worth mentioning that the handlebar library https://github.com/jknack/handlebars.java can trivialize many transformation tasks include toCSV.
You can use gererics to work for any class
public class FileUtils<T> {
public String createReport(String filePath, List<T> t) {
if (t.isEmpty()) {
return null;
}
List<String> reportData = new ArrayList<String>();
addDataToReport(t.get(0), reportData, 0);
for (T k : t) {
addDataToReport(k, reportData, 1);
}
return !dumpReport(filePath, reportData) ? null : filePath;
}
public static Boolean dumpReport(String filePath, List<String> lines) {
Boolean isFileCreated = false;
String[] dirs = filePath.split(File.separator);
String baseDir = "";
for (int i = 0; i < dirs.length - 1; i++) {
baseDir += " " + dirs[i];
}
baseDir = baseDir.replace(" ", "/");
File base = new File(baseDir);
base.mkdirs();
File file = new File(filePath);
try {
if (!file.exists())
file.createNewFile();
} catch (Exception e) {
e.printStackTrace();
return isFileCreated;
}
try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream(file), System.getProperty("file.encoding")))) {
for (String line : lines) {
writer.write(line + System.lineSeparator());
}
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
void addDataToReport(T t, List<String> reportData, int index) {
String[] jsonObjectAsArray = new Gson().toJson(t).replace("{", "").replace("}", "").split(",\"");
StringBuilder row = new StringBuilder();
for (int i = 0; i < jsonObjectAsArray.length; i++) {
String str = jsonObjectAsArray[i];
str = str.replaceFirst(":", "_").split("_")[index];
if (i == 0) {
if (str != null) {
row.append(str.replace("\"", ""));
} else {
row.append("N/A");
}
} else {
if (str != null) {
row.append(", " + str.replace("\"", ""));
} else {
row.append(", N/A");
}
}
}
reportData.add(row.toString());
}

Categories