From what i read on the Net: PDG or SDG can give me a tree of dependecies i tried with a simple exemple but i have no result
what i did :
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Iterator;
import org.objectweb.asm.tree.analysis.AnalyzerException;
import com.graph.element.Node;
import com.graph.internal.NodeNotFoundException;
import com.graph.sdg.SystemDependenceGraph;;
public class A {
public static void main(String[] args) throws FileNotFoundException, IOException, AnalyzerException, NodeNotFoundException {
SystemDependenceGraph lvSystemDependenceGraph
=new SystemDependenceGraph("C:\\Users\\amina\\workspace\\SDG\\fact","C:\\Users\\amina\\workspace\\SDG\\fact\\bin\\Fact.class");
Iterator<Node> lvIterator =lvSystemDependenceGraph.controlDependenceBFSIterator();
while (lvIterator.hasNext()) {
Node lvNode = lvIterator.next();
}
}
}
class fact :
public class Fact {
public static void main(String[] args) {
int f;
int n;
n=4;
f=1;
while(n!=0){
f=f*n;
n=n-1;
}
System.out.println("f= "+f+" n= "+n);
}
}
when i run class A there is no result
SDG is a java library for analyzing java code. It processes the java sources/byte code, converts into a graph. If you iterate with either BFS or DFS, it gives you series of instruction(code) including the callee method instructions.
In the above example, Class A is iterating over the instructions. Every Node is a instruction there. After retrieving node, you are not printing it so there is no output for the above class.
If you add below line, then it works.
System.out.println("Instruction is " + node.getName());
There are other methods in the Node class like sourceline(getLine()), source is a caller or not (getCaller), what is the instruction type (getType()) etc...
Related
I have a java file name E2BXmlParser where I am reading and manipulating the XML data fetched from the database.
Now I am trying to execute the java file using Oracle SQL Developer after changing the file like this
CREATE AND COMPILE JAVA SOURCE NAMED "E2BXmlParser" AS
--(Rest of Code).
And rest of code looks like this--
import oracle.jdbc.*
import oracle.xdb.XMLType;
import oracle.xml.parser.v2.XMLDocument;
import oracle.jdbc.*;
import org.w3c.dom.*;
import org.xml.sax.InputSource;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.*;
import java.sql.Connection;
import java.util.*
import javax.xml.xpath.*;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.io.StringReader;
class Reaction {
}
public class E2BXmlParser {
//variables
public E2BXmlParser(int regReportId, int reportId) {
//connection
}
public static void parseXML(int regReportId, int reportId, int isBlinded, int reportFormid,int pi_is_r3_profile,int pi_max_length,String pi_risk_category) throws SQLException, XPathExpressionException, TransformerException {
//fetching data
}
private static Document getDocumentFromString(String xmlContent) throws Exception {
}
private String getStringByElementName(String tagName, Element element) {
}
private OracleConnection getConnecton() {
//oracle connection
}
private Document getXmlDocumentFromDb(int regReportId, int reportId) {
//fetching and manipulating data
}
private List<Reaction> getReactionIds() {
//logic
}
private void findById(Reaction reaction, String id) {
//xpath for finding nodes
}
private boolean checkNodeExists(Element el, String nodeName) {
NodeList list = el.getElementsByTagName(nodeName);
return list.getLength() > 0;
}
private void updateNode(Reaction reaction, Element el) {
//update xml
}
private void updateXmlInDB(int regReportId, int reportId) throws SQLException {
//update xml in db
}
private void updateDrugNode() {
Element rootElement = document.getDocumentElement();
//logic
}
private void updateDrugEventandDrugRelatedness(int reportFormid) {
//update xml
}
private void updateMedicinalActiveSubstance(int regReportId, int isBlinded, int reportFormid,int pi_is_r3_profile,int pi_max_length,String pi_risk_category) {
//update xml after fetching data and changing in DB
}
private Boolean compareStrings(String strOne, String strTwo) {
//logic
}
private void updateDosageInformation() {
//logic
}
private void updateActiveSubstanceName() {
updating activesubstance using xpath
}
private void RemoveDuplicateActiveSubstance(NodeList activesubstancenameList, List<String> names) {
// logic
}
}
Now it is asking for multiple values(reactions,nodelist,node) that are used in code.
But this is not the case
when I am executing the java file from command line like this
loadjava -user username/password#DBalias -r E2BXmlParser.java
P.S I have to change my E2BXmlParser.java file to E2BXmlParser.sql file so that I can execute it from oracle sql developer.
Please help.
The easiest solution is wrapping all logic of your class into one static method in class. Next you have to publish this method to pl sql.
And publication of static function will be look (more or less) like this.
CREATE PROCEDURE parseXML (regReportId NUMBER, reportId NUMBER, isBlinded NUMBER, reportFormid NUMBER, pi_is_r3_profile NUMBER, pi_max_length NUMBER, pi_risk_category varchar2)
AS LANGUAGE JAVA
NAME 'E2BXmlParser.parseXML(int regReportId, int reportId, int isBlinded, int reportFormid,int pi_is_r3_profile,int pi_max_length,java.lang.String pi_risk_category)';
Note. In plsql you have to use full path to object example String -> java.lang.String
Of course oracle allows to use java class in more object oriented way but this is more complicated.
For more information check this manual. https://docs.oracle.com/cd/E18283_01/java.112/e10588/toc.htm
Chapter 3 (Calling Java Methods in Oracle Database) - for basic solutions.
Chapter 6 (Publishing Java Classes With Call Specifications) - ( paragraph Writing Object Type Call Specifications) - for publishing full java class.
In my hard drive I have follow source:
package DAO;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.CountDownLatch;
public abstract class A {
public class A4{
public String teste4(int i){
return (new String("teste"));
}
}
public class A3{
public String teste3(int i){
return (new String("teste"));
}
public A4 teste33(int i){
return (new A4());
}
}
public class A2{
public A3 teste2(int i){
return (new A3());
}
}
public class A1{
public A2 teste1(int i){
return (new A2());
}
}
public int[] toIntArray(List<Integer> list) {
A1 q=new A1();
Integer t=q.teste1(
(new A1()).
teste1(0).
teste2(0).
teste33(0).
teste4(0).
length() ).
teste2(0).
teste3(0).
length();
}
}
Note that in this file (A.java) we have many blank lines and one command not necessarily was written in the same line, in others words, it's maybe spread in many lines (See last line of method "toIntArray").
When I parse this source code with AST, the "toString" of "CompilationUnit"show the follow struct (AST Struct):
package DAO;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.CountDownLatch;
public abstract class A {
public class A4 {
public String teste4( int i){
return (new String("teste"));
}
}
public class A3 {
public String teste3( int i){
return (new String("teste"));
}
public A4 teste33( int i){
return (new A4());
}
}
public class A2 {
public A3 teste2( int i){
return (new A3());
}
}
public class A1 {
public A2 teste1( int i){
return (new A2());
}
}
public int[] toIntArray( List<Integer> list){
A1 q=new A1();
Integer t=q.teste1((new A1()).teste1(0).teste2(0).teste33(0).teste4(0).length()).teste2(0).teste3(0).length();
}
}
Note that in this case, all blank lines was removed and the command "Integer t=q.teste1...." was write in the same line. It's fine to me. Thus, in visit "MethodInvocation", I want to get line number of these invocations. To do this, I make follow source in my astVisitors:
public boolean visit(final CompilationUnit node) {
this.CompilationUnit=node;
}
public boolean visit(final MethodInvocation node) {
Integer LineInFile=this.CompilationUnit.getLineNumber(node.getStartPosition());
}
But the command "getLineNumber" return Line Number in source file in my hard drive, not in AST Struct. In this case, to the line "q.teste1((new.....", the command "getLineNumber" return the lines 44 and 45, but want that this return only the line 44.
So, How get de line number in "AST Struct"?
The CompilationUnit.toString method is just doing a rough format of the internal AST using the NaiveASTFlattener class.
The actual internal structure of the AST is just a large number of class instances of things like Block, Comment, Statement, ... As such the AST itself does not have line numbers. The only line numbers the AST knows about are the lines in the original source code.
We may start by expanding AST to "abstract syntax tree", which emphasizes that we have no (direct) connection to the source level (=concrete) syntax. You may call it a "model", which captures the semantically relevant aspects, while omitting accidental details like white space. A language could even rename its keywords without any changes to the abstract syntax etc.
It's a convenience for users, that a CompilationUnit additionally stores the positions of line ends, so it can map an AST node back to its original location in the source code.
How can I count my messages? I have both classes in the same folder and I compile them in the terminal. I don't want to install an IDE and create a package.
My counting class:
import java.util.ArrayList;
public class countMessages{
public static void main(String args[]){
int count = messages.size();
}
}
My message containing class:
import java.util.ArrayList;
public class SampleDataBase {
public static ArrayList<String> messages;
static {
messages = new ArrayList<String>(12);
messages.add("A "+"message "+"with "+"pineapples.");
messages.add("A "+"message "+"with "+"grapes.");
messages.add("A "+"message "+"with "+"watermelons.");
}
}
To create a package just create a folder (name it for example myPackage) and put both classes in it. Also include a first line in both class files: package myPackage;. Remember to name the class files with the names of the classes.
To make your example work just change messages.size(); to SampleDataBase.messages.size();.
And you really should name the class CountMessages with a capital letter.
It's unclear what you are trying to do but what I think you are looking for is a main static method(?)
import java.util.ArrayList;
public class SampleDataBase
{
public static void main(String[] args)
{
ArrayList<String> messages = new ArrayList<>();
messages.Add("things...");
for(String message : messages)
{
System.out.println(message);
}
System.out.println("The number of messages is : " + messages.size());
}
}
in the terminal, to use:
Compile javac *.java
Execute java SampleDataBase
If you want to keep two classes, use this on your test class(that contains main method).
public class countMessages{
public static void main(String args[]){
// You must instantiate the other class
SampleDataBase sdb = new SampleDataBase();
// here you will get the total messages in your arrayList
int count = sdb.messages.size();
}
With Java7 and Java8, I would like to generate a warning if some methods was called.
The warning will be print if a specific jar is present when then user compile.
I write an Annotation Processor and catch the visitMethodInvocation(). Now, I want extract the class and method names will be invoked.
Is it possible to do that ?
Or how to approach this?
You can do something like:
package mystuff;
import com.sun.source.tree.*;
import com.sun.source.util.*;
import java.util.*;
import javax.annotation.processing.*;
import javax.lang.model.element.*;
import javax.tools.*;
#SupportedAnnotationTypes("*")
public class Proc extends AbstractProcessor{
#Override
public boolean process(Set<?extends TypeElement>annotations,RoundEnvironment roundEnvironment){
final Trees trees=Trees.instance(processingEnv);
for(Element element:roundEnvironment.getRootElements()){
TreePath path=trees.getPath(element);
final CompilationUnitTree compilationUnit=path.getCompilationUnit();
compilationUnit.accept(new TreeScanner<Object,Object>(){
#Override
public Object visitMethodInvocation(MethodInvocationTree tree,Object data){
tree.getMethodSelect().accept(new SimpleTreeVisitor<Object,Object>(){
#Override
public Object visitMemberSelect(MemberSelectTree tree,Object data){
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,String.format("class: %1$s\nmethod: %2$s",tree.getExpression(),tree.getIdentifier()));
return null;
}
},null);
return null;
}
},null);
}
return true;
}
}
I used that processor to process the below class
package stuff;
import java.util.*;
#MyAnnotation
class MyProgram{
public void run(){
System.out.println("Hello World!");
}
}
and achieved this result:
class: System.out
method: println
I am pretty sure that the method name generated is what you are looking for. I am pretty sure that the "class" is not exactly what you are looking for, but is a pretty good start.
In my example you probably wanted it to print "java.io.PrintStream" for the class. To get that you could use processingEnv.getElementUtils().getTypeElement("java.lang.System") to get a TypeElement representing the system class. Then you can use processingEnv.getElementUtils().getAllMembers() to get every single member of the system class. Iterate through that to find out. Use the asType method to get its type.
The preceding paragraph was a gross simplification. The processor did not know a priori that out is a static member of a class that is part of the implicitly imported java.lang package. So your code will have to try and fail to find the following classes System and java.util.System (because it is in the imports), System.out, java.util.System.out, and java.lang.System.out.
I only dealt with MemberSelect. You will have to deal with other possibilities including MethodInvocation. For example new Object().toString().hashCode() should be class=Object, method=hashCode.
As an alternative to the great answer from #emory, you can consider using the pluggable type-checking annotation processing provided by the Checker Framework. The advantage is it can help you to easily determinate the type of the method invoker. Here is an example processor based on the checker framework (add checker.jar to the classpath when compile).
#SupportedAnnotationTypes("*")
#SupportedSourceVersion(SourceVersion.RELEASE_8)
public class MyTypeProcessor extends AbstractTypeProcessor {
class MyTreePathScanner extends TreePathScanner<Void, Void> {
private final Trees trees;
private final TreePath root;
public MyTreePathScanner(TreePath root) {
this.trees = Trees.instance(processingEnv);
this.root = root;
}
#Override
public Void visitMemberSelect(MemberSelectTree node, Void aVoid) {
ExpressionTree expression = node.getExpression();
TreePath expr = TreePath.getPath(root, expression);
TypeMirror type = trees.getTypeMirror(expr);
Element typeElement = processingEnv.getTypeUtils().asElement(type);
Optional<? extends Element> invoker = typeElement.getEnclosedElements().stream().filter(
e -> e.getSimpleName().equals(node.getIdentifier())).findFirst();
if (invoker.isPresent() && invoker.get().getKind() == ElementKind.METHOD) {
System.out.println("Type: " + typeElement + ", method: " + invoker.get());
}
return super.visitMemberSelect(node, aVoid);
}
}
#Override
public void typeProcess(TypeElement typeElement, TreePath root) {
new MyTreePathScanner(root).scan(root, null);
}
}
Which is processing the following input source.
public class Test {
public void foo() {
}
public static void main(String[] args) {
System.out.println("Hello world!");
Test t = new Test();
t.foo();
}
}
Here is the output:
Type: java.io.PrintStream, method: println()
Type: Test, method: foo()
I have taken all of my classes from my intro to java college in highschool class, and put them into a package called gameChoices. I then made a class that would call these classes when the user asks for them, this is called whichGame. I've imported the classes I want called using import gameChoices."whatever game it is";. How do I call these classes in whichGame? I also have them all as public static main(string [] args), which ones shouldn't have that(I think it's just whichGame that should..)? And what would I put instead? Thanks for helping a newbie out :)
The simplest way to do it is probably to set up a big if/then statement.
if(input.equals("t"))
thisOne.start();
else if(input.equals("a"))
anotherOne.start();
else if(input.equals("y"))
yetAnotherOne.start();
And so on. Might be a pain if you have a lot of classes, or if they start with the same letter.
Not sure exactly what you want to achieve, but if you need to access a class by its name you can try Class.forName() and check for exceptions thrown (particularly, ClassNotFoundException).
Using case-insensitive String equality for the name check, if would allow you to access any existing class of your ClassLoader through reflection.
Edit
Here's your main class:
package test;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
public class Main {
// initializes your map of letter->game class
private static final Map<String, Class<?>> GAMES = new HashMap<String, Class<?>>();
// constant name of main method for your games
private static final String MAIN_METHOD_NAME = "main";
// add your games
static {
GAMES.put("c", Chess.class);
GAMES.put("d", Doom.class);
// TODO moar gamez
}
public static void main(String[] args) {
try {
// prompts the user
System.out.println("Enter the game's name or starting letter: ");
BufferedReader br = new BufferedReader(
new InputStreamReader(System.in)
);
// gets the response
String input = br.readLine();
br.close();
// iterates over your games' first letters
for (String gameName : GAMES.keySet()) {
// the input starts with one game's first letter...
if (gameName.startsWith(input.toLowerCase())) {
// gets the class
GAMES.get(gameName)
// gets its main method (typical signature is String[] args)
.getMethod(MAIN_METHOD_NAME, String[].class)
// invokes its main method with no arguments
.invoke((Object) null, (Object) null);
}
}
// handles any disaster
} catch (Throwable t) {
t.printStackTrace();
}
}
}
Now here are two "game" classes:
package test;
public class Chess {
public static void main(String[] args) {
System.out.println("You've chosen Chess!");
}
}
... and...
package test;
public class Doom {
public static void main(String[] args) {
System.out.println("You've chosen Doom!");
}
}
Now set your "Main" class as your... main class.
When you launch the application, it will query you for an initial letter.
If you choose "c" or "d", it will print out: "You've chosen [Chess/Doom]!"
I hope this helps you getting started.