Convert static windows library to dll - java

I have a library contains a bunch of static *lib files, I wish to access them from JNA (a Java library that allows one to dynamically call `dll's from JAVA Code), so is there a way to magically change static lib to dll?
Code was compiled using Visual studio (hope that is relevant), and I also have appropriate header files.
I do not have access to source code, also I would like to do it using only free (as in beer) tools.

I'm not aware of anyb tools that will do this automatically, but the process is to create a DLL project and add your libraries to the project. For each function in the header file:
int SomeLibFunc( int x, int y );
you would need to create and export your own function in the DLL;
int MyFunc( int x, int y ) {
return SomLibFunc( x, y );
}
The process is quite mechanical, and you may be able to knock up a script using something like perl to create the DLL source files.

Assuming you don't have access to the source, you can simply create a wrapper DLL that exports the functions you need and delegates to the static library.

I did as anon suggested, I did an automatic converter (someone suggested just putting _ddlspec(export) before declaration and compiling dll with this header would work -- well it didn't -- maybe i did something wrong -- I'm Plain Old Java Programmer ;)):
it basically parses header files and turns:
SADENTRY SadLoadedMidFiles( HMEM, USHORT usMaxMidFiles, VOID * );
to:
__declspec(dllexport) SADENTRY DLL_WRAPPER_SadLoadedMidFiles(HMEM param0,
USHORT usMaxMidFiles, VOID* param2){
return SadLoadedMidFiles(param0, usMaxMidFiles, param2);
}
Here is the code (most probably its Regexp abuse, but it works), gui part depends on MigLayout:
package cx.ath.jbzdak.diesIrae.util.wrappergen;
import net.miginfocom.swing.MigLayout;
import javax.swing.*;
import static java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Displays a window. In this window you have to specify two things:
* <p/>
* 1. Name of header file that you want to process.
* <p/>
* 2. Name of output files extension will be added automatically. We will override any existing files.
*
* <p/>
* Dependencies: MigLayout
* <p/>
* Actual wrapper generation is done inside WrapperGen class.
* <p/>
* KNOWN ISSUES:
* <p/>
* 1. Ignores preprocessor so may extract finction names that are inside <code>#if false</code>.
* <p/>
* 2. Ignores comments
* <p/>
* 3. May fail to parse werid parameter syntax. . .
*
* Created by IntelliJ IDEA.
* User: Jacek Bzdak
*/
public class WrapperGenerator {
public static final Charset charset = Charset.forName("UTF-8");
WrapperGen generator = new WrapperGen();
// GUI CODE:
File origHeader, targetHeader, targetCpp;
JTextField newHeaderFileName;
JFrame wrapperGeneratorFrame;
{
wrapperGeneratorFrame = new JFrame();
wrapperGeneratorFrame.setTitle("Zamknij mnie!"); //Wrapper generator
wrapperGeneratorFrame.setLayout( new MigLayout("wrap 2, fillx", "[fill,min!]"));
wrapperGeneratorFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ActionListener buttonListener = new ActionListener() {
JFileChooser fileChooser = new JFileChooser();
{
fileChooser.setFileFilter(new javax.swing.filechooser.FileFilter() {
#Override
public boolean accept(File f) {
return f.isDirectory() || f.getName().matches(".*\\.h(?:pp)?");
}
#Override
public String getDescription() {
return "Header files";
}
});
fileChooser.setCurrentDirectory(new File("C:\\Documents and Settings\\jb\\My Documents\\Visual Studio 2008\\Projects\\dll\\dll"));
}
public void actionPerformed(ActionEvent e) {
if(JFileChooser.APPROVE_OPTION == fileChooser.showOpenDialog(wrapperGeneratorFrame)){
origHeader = fileChooser.getSelectedFile();
}
}
};
wrapperGeneratorFrame.add(new JLabel("Original header file"));
JButton jButton = new JButton("Select header file");
jButton.addActionListener(buttonListener);
wrapperGeneratorFrame.add(jButton);
wrapperGeneratorFrame.add(new JLabel("Result files prefix"));
newHeaderFileName = new JTextField("dll_wrapper");
wrapperGeneratorFrame.add(newHeaderFileName);
ActionListener doListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
targetHeader = new File(origHeader.getParentFile(), newHeaderFileName.getText() + ".h");
targetCpp = new File(origHeader.getParentFile(), newHeaderFileName.getText() + ".cpp");
try {
targetHeader.createNewFile();
targetCpp.createNewFile();
generator.reader = new InputStreamReader(new FileInputStream(origHeader),charset);
generator.cppWriter = new OutputStreamWriter(new FileOutputStream(targetCpp), charset);
generator.heaerWriter = new OutputStreamWriter(new FileOutputStream(targetHeader), charset);
generator.parseReader();
} catch (IOException e1) {
e1.printStackTrace();
JOptionPane.showMessageDialog(wrapperGeneratorFrame, "ERROR:" + e1.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
return;
}
}
};
JButton go = new JButton("go");
go.addActionListener(doListener);
wrapperGeneratorFrame.add(go, "skip 1");
}
public static void main(String []args){
SwingUtilities.invokeLater(new Runnable() {
public void run() {
WrapperGenerator wgen = new WrapperGenerator();
JFrame f = wgen.wrapperGeneratorFrame;
wgen.wrapperGeneratorFrame.pack();
Point p = getLocalGraphicsEnvironment().getCenterPoint();
wgen.wrapperGeneratorFrame.setLocation(p.x-f.getWidth()/2, p.y-f.getHeight()/2);
wgen.wrapperGeneratorFrame.setVisible(true);
}
});
}
}
/**
* Does the code parsing and generation
*/
class WrapperGen{
/**
* Method is basically syntax like this: <code>(anything apart from some special chars like #;) functionName(anything)</code>;
* Method declarations may span many lines.
*/
private static final Pattern METHOD_PATTERN =
//1 //2 //params
Pattern.compile("([^#;{}]*\\s+\\w[\\w0-9_]+)\\(([^\\)]*)\\);", Pattern.MULTILINE);
//1 - specifiers - including stuff like __dllspec(export)...
//2 - function name
//3 param list
/**
* Generated functions will have name prefixet with #RESULT_PREFIX
*/
private static final String RESULT_PREFIX = "DLL_WRAPPER_";
/**
* Specifiers of result will be prefixed with #RESULT_SPECIFIER
*/
private static final String RESULT_SPECIFIER = "__declspec(dllexport) ";
Reader reader;
Writer heaerWriter;
Writer cppWriter;
public void parseReader() throws IOException {
StringWriter writer = new StringWriter();
int read;
while((read = reader.read())!=-1){
writer.write(read);
}
reader.close();
heaerWriter.append("#pragma once\n\n\n");
heaerWriter.append("#include \"stdafx.h\"\n\n\n"); //Standard Visual C++ import file.
cppWriter.append("#include \"stdafx.h\"\n\n\n");
Matcher m = METHOD_PATTERN.matcher(writer.getBuffer());
while(m.find()){
System.out.println(m.group());
handleMatch(m);
}
cppWriter.close();
heaerWriter.close();
}
public void handleMatch(Matcher m) throws IOException {
Method meth = new Method(m);
outputHeader(meth);
outputCPP(meth);
}
private void outputDeclaration(Method m, Writer writer) throws IOException {
//writer.append(RESULT_SPECIFIER);
writer.append(m.specifiers);
writer.append(" ");
writer.append(RESULT_PREFIX);
writer.append(m.name);
writer.append("(");
for (int ii = 0; ii < m.params.size(); ii++) {
Parameter p = m.params.get(ii);
writer.append(p.specifiers);
writer.append(" ");
writer.append(p.name);
if(ii!=m.params.size()-1){
writer.append(", ");
}
}
writer.append(")");
}
public void outputHeader(Method m) throws IOException {
outputDeclaration(m, heaerWriter);
heaerWriter.append(";\n\n");
}
public void outputCPP(Method m) throws IOException {
cppWriter.append(RESULT_SPECIFIER);
outputDeclaration(m, cppWriter);
cppWriter.append("{\n\t");
if (!m.specifiers.contains("void") || m.specifiers.matches(".*void\\s*\\*.*")) {
cppWriter.append("return ");
}
cppWriter.append(m.name);
cppWriter.append("(");
for (int ii = 0; ii < m.params.size(); ii++) {
Parameter p = m.params.get(ii);
cppWriter.append(p.name);
if(ii!=m.params.size()-1){
cppWriter.append(", ");
}
}
cppWriter.append(");\n");
cppWriter.append("}\n\n");
}
}
class Method{
private static final Pattern NAME_REGEXP =
//1 //2
Pattern.compile("\\s*(.*)\\s+(\\w[\\w0-9]+)\\s*", Pattern.MULTILINE);
//1 - all specifiers - including __declspec(dllexport) and such ;)
//2 - function name
public final List<Parameter> params;
public final String name;
public final String specifiers;
public Method(Matcher m) {
params = Collections.unmodifiableList(Parameter.parseParamList(m.group(2)));
Matcher nameMather = NAME_REGEXP.matcher(m.group(1));
System.out.println("ALL: " + m.group());
System.out.println("G1: " + m.group(1));
if(!nameMather.matches()){
throw new IllegalArgumentException("for string " + m.group(1));
}
// nameMather.find();
specifiers = nameMather.group(1);
name = nameMather.group(2);
}
}
class Parameter{
static final Pattern PARAMETER_PATTERN =
//1 //2
Pattern.compile("\\s*(?:(.*)\\s+)?([\\w\\*&]+[\\w0-9]*[\\*&]?)\\s*");
//1 - Most probably parameter type and specifiers, but may also be empty - in which case name is empty, and specifiers are in 2
//2 - Most probably parameter type, sometimes prefixed with ** or &* ;), also
// 'char *' will be parsed as grup(1) == char, group(2) = *.
/**
* Used to check if group that represenrs parameter name is in fact param specifier like '*'.
*/
static final Pattern STAR_PATTERN =
Pattern.compile("\\s*([\\*&]?)+\\s*");
/**
* If
*/
static final Pattern NAME_PATTERN =
Pattern.compile("\\s*([\\*&]+)?(\\w[\\w0-9]*)\\s*");
public final String name;
public final String specifiers;
public Parameter(String param, int idx) {
System.out.println(param);
Matcher m = PARAMETER_PATTERN.matcher(param);
String name = null;
String specifiers = null;
if(!m.matches()){
throw new IllegalStateException(param);
}
name = m.group(2);
specifiers = m.group(1);
if(specifiers==null || specifiers.isEmpty()){ //Case that parameter has no name like 'int', or 'int**'
specifiers = name;
name = null;
}else if(STAR_PATTERN.matcher(name).matches()){ //Case that parameter has no name like 'int *'
specifiers += name;
name = null;
}else if(NAME_PATTERN.matcher(name).matches()){ //Checks if name contains part of type like '**ptrData', and extracts '**'
Matcher m2 = NAME_PATTERN.matcher(name);
m2.matches();
if(m2.group(1)!=null){
specifiers += m2.group(1);
name = m2.group(2);
}
}
if(name==null){
name = "param" + idx;
}
this.specifiers = specifiers;
this.name = name;
}
public static List<Parameter> parseParamList(String paramList){
List<Parameter> result = new ArrayList<Parameter>();
String[] params = paramList.split(",");
int idx = 0;
for(String param : params){
Parameter p = new Parameter(param, idx++);
result.add(p);
}
if(result.size()==1){
Parameter p = result.get(0);
if(p.specifiers.matches("\\s*void\\s*")){
return Collections.emptyList();
}
}
return result;
}
}

Related

Find methods with modified code between two versions of a Java class

I'd like to find the methods which changed between two arbitrary Java files.
What I've Tried
I've tried using diff (GNU diffutils 3.3) to find changes to lines in the file and diff --show-c-function connect those lines to the changed method. Unfortunately, in Java this lists the class, not the function.
I also tried git diff which seems to properly be able to find the changed function (at least as displayed on GitHub), but it doesn't always list the full signature and my files are not in the same Git repository (https://github.com/apache/commons-math/commit/34adc606601cb578486d4a019b4655c5aff607b5).
Desired Results
Input:
~/repos/d4jBugs/Math_54_buggy/src/main/java/org/apache/commons/math/dfp/Dfp.java
~/repos/d4jBugs/Math_54_fixed/src/main/java/org/apache/commons/math/dfp/Dfp.java
State of Files:
The changed methods between those two files are public double toDouble() and protected Dfp(final DfpField field, double x)
Output: (fully qualified names)
org.apache.commons.math.dfp.Dfp.toDouble()
org.apache.commons.math.dfp.Dfp(final DfpField field, double x)
Summary
Can I find the modified methods with the GNU diffutils tool or git diff and if yes, how would I do that? (Note: I'm not bound to those tools and am happy to install something else if needed.)
I used JavaParser 3.4.4, but it probably works but has not been tested with other versions.
It can be imported in Gradle with:
compile group: 'com.github.javaparser', name: 'javaparser-core', version: '3.4.4'
You can use my class like:
HashSet<String> changedMethods = MethodDiff.methodDiffInClass(
oldFileNameWithPath,
newFileNameWithPath
);
MethodDiff Source:
import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.body.CallableDeclaration;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.ConstructorDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.comments.Comment;
import com.github.javaparser.printer.PrettyPrinterConfiguration;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
/**
* Created by Loren Klingman on 10/19/17.
* Finds Changes Between Methods of Two Java Source Files
*/
public class MethodDiff {
private static PrettyPrinterConfiguration ppc = null;
class ClassPair {
final ClassOrInterfaceDeclaration clazz;
final String name;
ClassPair(ClassOrInterfaceDeclaration c, String n) {
clazz = c;
name = n;
}
}
public static PrettyPrinterConfiguration getPPC() {
if (ppc != null) {
return ppc;
}
PrettyPrinterConfiguration localPpc = new PrettyPrinterConfiguration();
localPpc.setColumnAlignFirstMethodChain(false);
localPpc.setColumnAlignParameters(false);
localPpc.setEndOfLineCharacter("");
localPpc.setIndent("");
localPpc.setPrintComments(false);
localPpc.setPrintJavadoc(false);
ppc = localPpc;
return ppc;
}
public static <N extends Node> List<N> getChildNodesNotInClass(Node n, Class<N> clazz) {
List<N> nodes = new ArrayList<>();
for (Node child : n.getChildNodes()) {
if (child instanceof ClassOrInterfaceDeclaration) {
// Don't go into a nested class
continue;
}
if (clazz.isInstance(child)) {
nodes.add(clazz.cast(child));
}
nodes.addAll(getChildNodesNotInClass(child, clazz));
}
return nodes;
}
private List<ClassPair> getClasses(Node n, String parents, boolean inMethod) {
List<ClassPair> pairList = new ArrayList<>();
for (Node child : n.getChildNodes()) {
if (child instanceof ClassOrInterfaceDeclaration) {
ClassOrInterfaceDeclaration c = (ClassOrInterfaceDeclaration)child;
String cName = parents+c.getNameAsString();
if (inMethod) {
System.out.println(
"WARNING: Class "+cName+" is located inside a method. We cannot predict its name at"
+ " compile time so it will not be diffed."
);
} else {
pairList.add(new ClassPair(c, cName));
pairList.addAll(getClasses(c, cName + "$", inMethod));
}
} else if (child instanceof MethodDeclaration || child instanceof ConstructorDeclaration) {
pairList.addAll(getClasses(child, parents, true));
} else {
pairList.addAll(getClasses(child, parents, inMethod));
}
}
return pairList;
}
private List<ClassPair> getClasses(String file) {
try {
CompilationUnit cu = JavaParser.parse(new File(file));
return getClasses(cu, "", false);
} catch (FileNotFoundException f) {
throw new RuntimeException("EXCEPTION: Could not find file: "+file);
}
}
public static String getSignature(String className, CallableDeclaration m) {
return className+"."+m.getSignature().asString();
}
public static HashSet<String> methodDiffInClass(String file1, String file2) {
HashSet<String> changedMethods = new HashSet<>();
HashMap<String, String> methods = new HashMap<>();
MethodDiff md = new MethodDiff();
// Load all the method and constructor values into a Hashmap from File1
List<ClassPair> cList = md.getClasses(file1);
for (ClassPair c : cList) {
List<ConstructorDeclaration> conList = getChildNodesNotInClass(c.clazz, ConstructorDeclaration.class);
List<MethodDeclaration> mList = getChildNodesNotInClass(c.clazz, MethodDeclaration.class);
for (MethodDeclaration m : mList) {
String methodSignature = getSignature(c.name, m);
if (m.getBody().isPresent()) {
methods.put(methodSignature, m.getBody().get().toString(getPPC()));
} else {
System.out.println("Warning: No Body for "+file1+" "+methodSignature);
}
}
for (ConstructorDeclaration con : conList) {
String methodSignature = getSignature(c.name, con);
methods.put(methodSignature, con.getBody().toString(getPPC()));
}
}
// Compare everything in file2 to what is in file1 and log any differences
cList = md.getClasses(file2);
for (ClassPair c : cList) {
List<ConstructorDeclaration> conList = getChildNodesNotInClass(c.clazz, ConstructorDeclaration.class);
List<MethodDeclaration> mList = getChildNodesNotInClass(c.clazz, MethodDeclaration.class);
for (MethodDeclaration m : mList) {
String methodSignature = getSignature(c.name, m);
if (m.getBody().isPresent()) {
String body1 = methods.remove(methodSignature);
String body2 = m.getBody().get().toString(getPPC());
if (body1 == null || !body1.equals(body2)) {
// Javassist doesn't add spaces for methods with 2+ parameters...
changedMethods.add(methodSignature.replace(" ", ""));
}
} else {
System.out.println("Warning: No Body for "+file2+" "+methodSignature);
}
}
for (ConstructorDeclaration con : conList) {
String methodSignature = getSignature(c.name, con);
String body1 = methods.remove(methodSignature);
String body2 = con.getBody().toString(getPPC());
if (body1 == null || !body1.equals(body2)) {
// Javassist doesn't add spaces for methods with 2+ parameters...
changedMethods.add(methodSignature.replace(" ", ""));
}
}
// Anything left in methods was only in the first set and so is "changed"
for (String method : methods.keySet()) {
// Javassist doesn't add spaces for methods with 2+ parameters...
changedMethods.add(method.replace(" ", ""));
}
}
return changedMethods;
}
private static void removeComments(Node node) {
for (Comment child : node.getAllContainedComments()) {
child.remove();
}
}
}

Java Array index out of bounds exception fix

I am currently getting an array out of bounds exception while executing the line name.firstName = this.firstNames[rand.nextInt(NUM_NAMES)]; Normally I dont have issues finding the source of these exceptions however I have been stuck on this one for some time now. Any help is appreciated, class and stacktrace are pasted below:
public class NameGenerator {
private static final int NUM_NAMES = 200;
private static final File NAMES_FILE = new File("resources/info.dat");
/** a random number generator */
private Random rand;
/** the array of first names */
private String[] firstNames;
/** the array of last names */
private String[] lastNames;
/**
* Default Constructor
*/
public NameGen() {
super();
this.rand = new Random();
try {
readFile();
} catch (IOException exp) {
this.first = new String[] { "foo" };
this.last = new String[] { "bar" };
}
}
/**
* Read the names from the file
*/
private void readNFiles() throws IOException {
List<String> tempFirst = new ArrayList<String>();
List<String> tempLast = new ArrayList<String>();
Scanner scnr = new Scanner(NAMES_FILE);
while (scnr.hasNext()) {
tempFirst.add(scnr.next());
tempLast.add(scnr.next());
}
scnr.close();
int size = tempFirst.size();
this.first = new String[size];
tempFirst.toArray(this.firstNames);
this.last = new String[size];
tempLast.toArray(this.last);
}
/**
* #return a generated name
*/
public FullName generateName() {
FullName name = new FullName();
name.first = this.firstNames[rand.nextInt()];
name.last = this.lastNames[rand.nextInt()];
return name;
}
/**
* Class describing a full name
*/
public static final class FullName {
/** the first name */
public String firstName;
/** the last name */
public String lastName;
}
}
Based on...
try {
readNamesFiles();
} catch (IOException exp) {
this.firstNames = new String[] { "John" };
this.lastNames = new String[] { "Doe" };
}
There is no guarantee that your arrays will contain NUM_NAMES elements (you should be logging the exception at the very least).
So using something like name.firstName = this.firstNames[rand.nextInt(NUM_NAMES)]; has the potional to cause some serious issues, as you've discovered.
Instead, you should work with reality instead of assumptions, using something more like...
name.firstName = this.firstNames[rand.nextInt(this.firstNames.length)];
Here is a summary of your problematic code:
List<String> tempFirstNames = new ArrayList<String>(NUM_NAMES);
int size = tempFirstNames.size();
this.firstNames = new String[size];
FullName name = new FullName();
name.firstName = this.firstNames[rand.nextInt(NUM_NAMES)];
You are using rand.nextInt(NUM_NAMES) as the array index into firstNames. This will generate a number between 0 and NUM_NAMES. The problem is that there is no guarantee that the array firstNames will have a size of NUM_NAMES. As the #AngryProgrammer pointed out, you can use this instead:
name.firstName = this.firstNames[rand.nextInt(firstNames.length)];

Extract ArrayList data from Textfile

I am trying to implement Dijkstra Algorithm that reads a DOT file (.txt) and should give back a map and first of all i have to extract Data from a textfile to an ArrayList, so I made two classes one for the Verticles, and the other Class for the Edges.
the text file looks like this :
Digraph {
A -> B [label="10,90"];
A -> C [label="8,80"];
C -> B [label="1,50"];
B -> D [label="7,60"];
C -> D [label="6,80"];
D -> E [label="4,90"];
E -> F [label="2,130"];
D -> F [label="5,130"];
F -> G [label="5,120"];
G -> H [label="5,100"];
A [label="A,5"];
B [label="B,4"];
C [label="C,3"];
D [label="D,2"];
E [label="E,1"];
F [label="F,6"];
G [label="G,7"];
H [label="H,8"];
}
for example in line 1 I should extract the Source which is "A" and the Destination which is "B" and the speedLimit which is 10 and the distance which is 90 this is concerning the edges. and from line 11 I should extract the name and time for example in the line 11 the name should be "A" and the time should be 5.
here is my simple first two classes :
VerticlesRep Class :
package lab;
public class VerticesRep {
private String name;
private int time;
public VerticesRep(String name, int time) {
this.name = name;
this.time = time;
}
public String getName() {
return name;
}
public int getTime() {
return time;
}
public void setName(String name) {
this.name = name;
}
public void setTime(int time) {
this.time = time;
}
}
and here is my EdgesRep Class :
package lab;
public class EdgesRep {
private String Source;
private String Destination;
private int speedLimit;
private int distance;
public EdgesRep(String Source, String Destination, int speedLimit, int distance) {
this.setSource(Source);
this.setDestination(Destination);
this.setSpeedLimit(speedLimit);
this.setDistance(distance);
}
public String getSource() {
return Source;
}
public void setSource(String source) {
Source = source;
}
public String getDestination() {
return Destination;
}
public void setDestination(String destination) {
Destination = destination;
}
public int getSpeedLimit() {
return speedLimit;
}
public void setSpeedLimit(int speedLimit) {
this.speedLimit = speedLimit;
}
public int getDistance() {
return distance;
}
public void setDistance(int distance) {
this.distance = distance;
}
}
and this is the Navigation Class :
package lab;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
/**
* The class Navigation finds the shortest (and/or) path between points on a map
* using the Dijkstra algorithm
*/
public class Navigation {
/**
* Return codes: -1 if the source is not on the map -2 if the destination is
* not on the map -3 if both source and destination points are not on the
* map -4 if no path can be found between source and destination
*/
public static final int SOURCE_NOT_FOUND = -1;
public static final int DESTINATION_NOT_FOUND = -2;
public static final int SOURCE_DESTINATION_NOT_FOUND = -3;
public static final int NO_PATH = -4;
// added variables
private String filename = null; // filename initialization
/**
* The constructor takes a filename as input, it reads that file and fill
* the nodes and edges Lists with corresponding node and edge objects
*
* #param filename
* name of the file containing the input map
*/
public Navigation(String filename) {
ArrayList<VerticesRep> Vertex = new ArrayList<VerticesRep>();
ArrayList<EdgesRep> Edges = new ArrayList<EdgesRep>();
this.filename = filename;
try {
FileReader fr = new FileReader(filename);
BufferedReader in = new BufferedReader(fr);
String line = null;
while ((line = in.readLine()) != null) {
// here i must fill the ArrayLists with the Information
// I need from the text file.
}
in.close();
fr.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
I tried to find out what I actually should use to fill the ArrayList from the text file but the .split won't actually work in my case.
Thank You.
Use regular expressions.
First import:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Then write something like this:
String line = null;
Pattern patternEdge = Pattern.compile("\\s*([A-Z])\\s*->\\s*([A-Z])\\s*\\[label=\"(\\d+),(\\d+)\"\\];");
Pattern patternVertex = Pattern.compile("\\s*([A-Z])\\s*\\[label=\"([A-Z]),(\\d+)\"\\];");
Matcher m = null;
while ((line = in.readLine()) != null) {
m = patternEdge.matcher(line);
if (m.find()) {
String source = m.group(1);
String destination = m.group(2);
int speedLimit = Integer.parseInt(m.group(3));
int distance = Integer.parseInt(m.group(4));
Edges.add(new EdgesRep(source, destination, speedLimit, distance));
}
else {
m = patternVertex.matcher(line);
if (m.find()) {
String name = m.group(2);
int time = Integer.parseInt(m.group(3));
Vertex.add(new VerticesRep(name, time));
}
else
System.err.println("Expression is incorrect. No matches");
}
}
//for debugging
for(EdgesRep e : Edges)
System.out.println(e.getSource() + " " + e.getDestination() + " " + e.getSpeedLimit() + " " + e.getDistance());
//for debugging
for(VerticesRep v : Vertex)
System.out.println(v.getName() + " " + v.getTime());
Because the first line doesn't really mean anything you may want to just skip it...
On this code block I assumed it starts with A -> B [label="10,90"];
Hope it helped :)

How to utlilize Error Collector for junit testing methods with parameters

I am using ErrorCollector in my Junit test case with the aim of printing out the errors and not stopping at the erroneous locations.
I successfully tried the ErrorCollector by using methods without parameters. However to reduce code duplicacy (i wrote the same method 6 times
without the parameter ; since i am using 6 files for comparison as seen in my code),
I would like to have a generic method that can be used to achieve the same purpose of printing out errors and continuing with the check.
When i tried using the method with a parameter i got the exception "Method should have no parameters"..
The following is my code.
import org.gdal172.ogr.ogr;
import org.hamcrest.CoreMatchers;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ErrorCollector;
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;
public class DGNTester {
private ReadDGN readDgn = new ReadDGN();
private LinkedHashMap<String, Integer> layerMapCountForCompare = new LinkedHashMap<String, Integer>();
#Rule
public ErrorCollector collector = new ErrorCollector();
private File output = null;
static {
// perform OGR format registration once
if (ogr.GetDriverCount() == 0)
ogr.RegisterAll();
}
/**
* #param args
*/
public static void main(String[] args) {
DGNTester dTest = new DGNTester();
String dgnFileName_43k10 = "input\\43k10.dgn";
String dgnFileName_43k11 = "input\\43k11.dgn";
String dgnFileName_43k12 = "input\\43k12.dgn";
//The six files iam using as input.
dTest.test(dgnFileName_43k10, "dvd");
dTest.test(dgnFileName_43k10, "all");
dTest.test(dgnFileName_43k11, "dvd");
dTest.test(dgnFileName_43k11, "all");
dTest.test(dgnFileName_43k12, "dvd");
dTest.test(dgnFileName_43k12, "all");
}
#Test
public void test(String fileName, String inputType) {
System.out.println("FOR FILE -->" + fileName);
System.out
.println("---------------------------------------------------------------------------------------------------");
String fileIdentifier = fileName.substring(6, 11);
String dstFilePath = null;
String outputName = null;
if (layerMapCountForCompare != null)
layerMapCountForCompare.clear();
if (inputType.equals("dvd")) {
dstFilePath = "F:\\eclipse_helios_3.6.1_64_bit_with_jre_and_add-ons\\eclipse\\Resources\\DST\\dvd.dst";
outputName = "output\\outputfile_" + fileIdentifier
+ "_dvd.dst.txt";
}
if (inputType.equals("all")) {
dstFilePath = "F:\\eclipse_helios_3.6.1_64_bit_with_jre_and_add-ons\\eclipse\\Resources\\DST\\AllLayers.dst";
outputName = "output\\outputfile_" + fileIdentifier + ".txt";
}
layerMapCountForCompare = readDgn.getLayerFeatureCount(fileName,
dstFilePath);
// Read the text output file and Compare with the map. These are the six out put files against each input file
output = new File(outputName);
if (output.exists()) {
try {
Set keys = layerMapCountForCompare.keySet();
Iterator itr = keys.iterator();
String key = "";
Integer val;
String line;
BufferedReader br = new BufferedReader(new FileReader(output));
while ((line = br.readLine()) != null && itr.hasNext()) {
key = (String) itr.next();
val = layerMapCountForCompare.get(key);
String compare = key + "=" + val;
compare.trim();
line.trim();
//When i print this out in a positive scenario; i am able to see the values of 'compare' and 'line' as same
/*System.out.println("COMPARE >>> " + compare
+ " --------------- AND --------- Line " + line);*/
assertEquals("Comparing input and output", line, compare);
}
br.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
System.out.println("Output file does not exist");
}
}
public void assertEquals(String msg, Object expected, Object actual) {
collector.checkThat(actual, CoreMatchers.equalTo(expected));
}
}
In my previous example; where i did not use parameters;
Result result = JUnitCore.runClasses(DGNTester.class);
for (Failure failure : result.getFailures()) {
System.out.println(failure.toString());
}
if (result.wasSuccessful()) {
System.out.println("Tests finished successfully...");
}
This code helped in triggering the test methods and print the appropriate methods.
Can you please guide me as to how I can use my generic method thet takes two parameters to utilize the ErrorCollector.
How to utlilize Error Collector for junit testing methods with parameters
The #Test annotation doesn't support test methods with parameters in the signature.
Example:
Trying to run the method brokenTest an exception will be thrown. A correct test method in JUnit should look like correctTest:
/** This method uses parameters in the signature. It will not work! */
#Test
public void brokenTest(String fileName) {...}
/** This correct test method has no parameters in its signature. */
#Test
public void correctTest() {...}
Parameterized tests with JUnit
To support parameterized testing you can use the #RunWith(Parameterized.class) annotation (class-level).
The test class needs a static method that returns the parameters in an Iterable (like a List object). Annotate this method with #Parameters.
Furthermore you need a public(!) member variable for each parameter used, each one annotated with #Parameter(0), #Parameter(1), and so on.
Thus JUnit will run testWithParameters() for each test case produced with the createParameters() method. It will automatically assign the correct parameters to the #Parameter(N) fields (firstParameter/secondParameter).
You can produce as many parameters as you need.
Use these parameters in your test methods as needed by refering to their field names.
Example with an excerpt of the class you provided:
#RunWith(Parameterized.class)
public class DGNTester {
#Rule
public ErrorCollector collector = new ErrorCollector();
/**
* Method that generates the parameters.
* Each testValues.add(...) line produces a new test case.
*
* #return Array with test values.
*/
#Parameters
public static Iterable<Object[]> createParameters() {
List<Object[]> testValues = new ArrayList<>();
try {
testValues.add(new Object[]{"pre-Case1-Value1", "Case1-Value2"});
testValues.add(new Object[]{"Case2-Param1", "Case2-Value2"});
testValues.add(new Object[]{"pre-Case3-Value1", "Case3-Value2"});
}
return testValues;
}
/** The first parameter. */
#Parameter(0)
public String firstParameter;
/** The second parameter. */
#Parameter(1)
public String secondParameter;
/** Test using the parameters generated by createParameters().
* In this example we check, if the first parameter is equal to the
* concatenation of the String "pre-" and the second parameter */
#Test
public void testWithParameters() {
assertThat("Wrong parameter values", firstParameter,
is("pre-" + secondParameter));
}
...
}

Writing CSV file. myPackage.MyClass cannot be cast to java.lang.CharSequence

I need to write List<MyClass> myList into CSV file. In particular I need to write values. MyClass has the following implementation:
public class MyClass {
private Object[] values;
//...
#Override
public String toString()
{
String line = "";
for (int i=0; i<this.getSize(); i++) {
//if (this.values[i] != null) {
line = line + this.values[i] + " ";
//}
}
return line;
}
}
The code is the following:
private void saveSolutionToCSV(List<MyClass> solution) {
int columnSize = solution.get(0).getSize();
try {
FileWriter writer = new FileWriter("test.csv");
Iterator result = solution.iterator();
while(result.hasNext()) {
for(int i = 0; i < columnSize; i++) {
CharSequence element = (CharSequence)result.next();
writer.append(element);
if(i < columnSize - 1)
writer.append(',');
}
writer.append('\n');
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
And the error message is the following:
java.lang.ClassCastException: myPackage.MyClass cannot be cast to java.lang.CharSequence
How to solve this problem? Thx.
Try:
String element = result.next().toString();
writer.append(element);
if(i < columnSize - 1)
writer.append(',');
You need to call toString() before casting to CharSequence.
Try calling the toString() method explicitly like
CharSequence element = (CharSequence)result.next().toString();
CsvWriter.java
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Collection;
/**
* Composes CSV data for collection of objects. Relays on theirs {#link Object#toString toString()} implementation.<br>
* Could use memory buffer for the data or write straight to the output stream.
* <p>
* Example 1:
*
* <pre>
* Object[][] data = ...
*
* CsvWriter writer = new CsvWriter();
* writer.write("Column 1", "Column 2", ... "Column N");
* for (Object[] values : data)
* writer.write(values);
* ...
* System.out.println(writer.toString());
* </pre>
* <p>
* Example 2:
*
* <pre>
* Object[][] data = ...
*
* CsvWriter writer = null;
* try {
* writer = new CsvWriter(new FileOutputStream(new File("data.csv")));
* writer.write("Column 1", "Column 2", ... "Column N");
* for (Object[] values : data)
* writer.write(values);
* } finally {
* writer.close();
* }
* </pre>
*
* #author Mykhaylo Adamovych
*/
public class CsvWriter implements Closeable {
public static final String NULL_MARK = "";
public static final String QUOTE = "\"";
private String nullMark = NULL_MARK;
private final PrintWriter pw;
private ByteArrayOutputStream baos;
/**
* Creates temporary buffer in the memory. <br>
* Use {#link #toString()} thereafter. No need to close.
*/
public CsvWriter() {
baos = new ByteArrayOutputStream();
pw = new PrintWriter(baos, true);
}
/**
* Doesn't consume memory for CSV data, writes straight to the output stream. Just like {#link FilterOutputStream}, but deal with objects and relays on
* theirs {#link Object#toString toString()} implementation.<br>
* Close writer thereafter.
*
* #param os
* output stream to write data.
*/
public CsvWriter(OutputStream os) {
pw = new PrintWriter(os, true);
}
protected String composeRecord(Object... values) {
if (values == null || values.length == 0)
return "";
final StringBuffer csvRecord = new StringBuffer();
csvRecord.append(QUOTE);
csvRecord.append(composeValue(values[0]));
csvRecord.append(QUOTE);
for (int i = 1; i < values.length; i++) {
csvRecord.append("," + QUOTE);
csvRecord.append(composeValue(values[i]));
csvRecord.append(QUOTE);
}
return csvRecord.toString();
}
protected String composeValue(Object value) {
if (value == null)
return nullMark;
return value.toString().replaceAll(QUOTE, QUOTE + QUOTE);
}
public String getNullMark() {
return nullMark;
}
public void setNullMark(String nullMarker) {
nullMark = nullMarker;
}
#Override
public String toString() {
if (baos == null)
throw new UnsupportedOperationException();
return baos.toString();
}
/**
* Writes collection of objects as CSV record.
*
* #param values
*/
public void write(Collection<?> values) {
write(values.toArray());
}
/**
* Writes collection of objects as CSV record.
*
* #param values
*/
public void write(Object... values) {
pw.println(composeRecord(values));
}
#Override
public void close() throws IOException {
if (baos != null)
throw new UnsupportedOperationException();
pw.close();
}
}
example:
public class MyClass {
private Object[][] data;
//...
#Override
public String toCsv() {
CsvWriter writer = new CsvWriter();
csvWriter.write("Column1", "Column2")
for (final Object[] values : data)
csvWriter.write(values);
return writer.toString();
}
}

Categories