I read java file using FileReader that contains some method. How i can read method scope (method area inside) to find duplicate variable?
For example, this is a java file that i read:
public double[] copyArray(double[] data) {
int _nn = data.length;
double[] _tmp = new double[_nn];
System.arraycopy(data, 0, _tmp, 0, _nn);
int _nn;
_nn = tmp;
return _tmp;
}
How to know method scope?, i mean between { and }, if scope has found, find duplicate variable such as example above (int _nn) duplicated.
[addition]
i have tried using java parser, then is success. Then i should send the results using list, but only last method in the list. What's wrong with my code?
This is a MethodVisitor:
private static class MethodVisitor extends VoidVisitorAdapter {
private List<String> list = new ArrayList<String>();
#Override
public void visit(MethodDeclaration n, Object file) {
list.add(n.getName());
}
public List<String> getList() {
return list;
}
}
Then, this is a method to call MethodVisitor:
private MethodVisitor mv;
public void doIt(File file) throws Exception {
CompilationUnit cu;
try {
// parse the file
cu = JavaParser.parse(file);
} finally {
//file.close();
}
// visit and print the methods names
mv = new MethodVisitor();
mv.visit(cu, file);
List<String> list = mv.getList();
for(String item:list){
System.out.println(item);
}
}
1 you need to parse java code:
http://code.google.com/p/javaparser/
or read this:
Java source code parsers/generators
2 after that, try something and show your code
Related
I've defined a arrayList as following
List<List<RiskyPersons>> dataArray = new ArrayList<>();
Here is RiskyPersons Class
public class RiskyPersons {
private SA3Tenant sa3tenant;
private int NumberofPersonInCategory;
public RiskyPersons(){
}
public RiskyPersons(SA3Tenant sa3tenant, int NumberofPersonInCategory) {
this.sa3tenant = sa3tenant;
this.NumberofPersonInCategory = NumberofPersonInCategory;
}
}
Then I've successfully added data and saved in dataArray ArrayList.
Following output is showing the saved ArrayList using SOP(dataArray);
[[RiskyPersons{sa3tenant=Homeless.SA3Tenant#3a7cc6b0, NumberofPersonInCategory=99}]]
I want to read this dataArray ArrayList and display values separately. How do I access "NumberofPersonInCategory" value?
From Java-8 and above one can use stream:
dataArray.stream()
.flatMap(List::stream)
.map(RiskyPersons::NumberofPersonInCategory)
.forEach(System.out::println)
I hope this will help you !
public class RiskyPersons {
private SA3Tenant sa3tenant;
private int NumberofPersonInCategory;
public int getNumberofPersonInCategory() {
return NumberofPersonInCategory;
}
public RiskyPersons(){
}
public RiskyPersons(SA3Tenant sa3tenant, int NumberofPersonInCategory) {
this.sa3tenant = sa3tenant;
this.NumberofPersonInCategory = NumberofPersonInCategory;
}
}
List<Integer> values = dataArray.parallelStream().flatMap(Collection::stream).map(RiskyPersons::getNumberofPersonInCategory)
.collect(Collectors.toCollection(ArrayList::new));
You'll need to iterate it twice as
for (List<RiskyPersons> rp : dataArray) {
for (RiskyPersons o : rp) {
System.out.println(o.NumberofPersonInCategory); // unrelated : but its bad naming convention
}
}
So basicly Im trying to add a simple System.out.println("hey");
at the end of a method. I used the tree API. I do however keep getting this error:
java.lang.VerifyError: Expecting a stackmap frame at branch target 38
This is my code:
public class MethodNodeCustom extends MethodNode {
public MethodNodeCustom(int paramInt, String paramString1, String paramString2, String paramString3, String[] paramArrayOfString) {
this(327680, paramInt, paramString1, paramString2, paramString3, paramArrayOfString);
return;
}
#SuppressWarnings({ "unchecked", "rawtypes" })
public MethodNodeCustom(int paramInt1, int paramInt2, String paramString1, String paramString2, String paramString3,
String[] paramArrayOfString) {
super(paramInt1);
this.access = paramInt2;
this.name = paramString1;
this.desc = paramString2;
this.signature = paramString3;
this.exceptions = new ArrayList((paramArrayOfString == null) ? 0 : paramArrayOfString.length);
int i = ((paramInt2 & 0x400) != 0) ? 1 : 0;
if (i == 0)
this.localVariables = new ArrayList(5);
this.tryCatchBlocks = new ArrayList();
if (paramArrayOfString != null)
this.exceptions.addAll(Arrays.asList(paramArrayOfString));
this.instructions = new InsnList();
}
#Override
public void visitEnd() {
AbstractInsnNode label = instructions.getLast();
instructions.remove(instructions.getLast());
instructions.remove(instructions.getLast());
visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", Type.getDescriptor(PrintStream.class));
visitLdcInsn("Cracked by damm ass pro skills");
visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
visitInsn(Opcodes.RETURN);
instructions.add(label);
super.visitEnd();
}
}
And this is my class node:
public class ClassNodeCustom extends ClassNode {
public ClassNodeCustom() {
super(ASMContentHandler.ASM4);
}
#SuppressWarnings("unchecked")
#Override
public MethodVisitor visitMethod(int paramInt, String paramString1, String paramString2, String paramString3, String[] paramArrayOfString) {
MethodNode localMethodNode = new MethodNodeCustom(paramInt, paramString1, paramString2, paramString3, paramArrayOfString);
this.methods.add(localMethodNode);
return localMethodNode;
}
}
And this is how I "inject" the code (I load it directly from the jar thats why it is using a zipFile)
InputStream in = zipFile.getInputStream(entry);
ClassReader cr = new ClassReader(in);
ClassNodeCustom node = new ClassNodeCustom();
cr.accept(node, 0);
ClassWriter cw = new ClassWriter(0);
node.accept(cw);
And like I said when ever I run it I get the verify error is there any way for me to solve it or any smarter way for me to "inject" that code ?
If you are adding code at the end of a method, you are adding it after its last instruction which is always a goto, switch, throw or return statement when compiling Java code. Even when compiling a method without an explicit return statement like
void foo() { }
you are actully compiling
void foo() { return; }
where the final return is implicit. With your additions, you change the method to
void foo() {
return;
System.out.println("hey");
}
Such unreachable code is forbidden by javac but perfectly legal in byte code. For unreachable code, it is however required that you are prepending it with a stack map frame that describes the state of the stack and the local variable array at that point. It would be easy enough to add a description of an empty frame at this point but I assume that you want to add the code before the return statement.
To implement this, ASM offers an AdviceAdapter that allows you to add code before return statements. As far as I know, there is nothing similar for the tree API but you can simply look for a return node within any method's instruction list and add the code prior to it.
I am currently trying to add a value to an ArrayList object from a method inside of another class.
Here is the class I have created for the ArrayList Object:
public class ArrayClass {
public static ArrayList<String> array = new ArrayList<>();
public static void add_val(String s){
array.add(s);
}
public static int get_size(){
return array.size();
}
public static String get_val(int i){
return array.get(i);
}
}
And the other class where I attempt to edit the ArrayList object:
ArrayClass fill = new ArrayClass();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_explore);
Response.Listener<String> responseListener4 = new Response.Listener<String>(){
#Override
public void onResponse(String response) {
try {
JSONObject jsonResponse4 = new JSONObject(response);
boolean success = jsonResponse4.getBoolean("success");
if (success){
int l;
String filled;
int length4 = jsonResponse4.length();
for (l=0;l<length4;l++){
filled = jsonResponse4.getString(l+"");
fill.add_val(filled);
}
}else{
AlertDialog.Builder builder = new AlertDialog.Builder(ExploreActivity.this);
builder.setMessage("Could not retrieve restaurant tables filled")
.setNegativeButton("Retry", null)
.create()
.show();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
};
FilledRequest filledRequest = new FilledRequest(responseListener4);
RequestQueue queue4 = Volley.newRequestQueue(ExploreActivity.this);
queue4.add(filledRequest);
If you look in the onResponse method, you can see the attempt to add a value from the jsonResponse into the ArrayClass object. However, when I launch my app, it does not add the value into the object. I'm used to python global variables and not having to deal with the semantics of java, so if you could shed some light on what changes need to be made, I would greatly appreciate it.
Apart from other given answers/solutions to the issue you are facing, let me share a best and optimized way to implement JSON parsing in Android.
I would suggest you to check GSON or Jackson libraries which provides Java serialization/deserialization that can convert Java Objects into JSON and back.
There are some benefits it does provide, one of the main benefits is you do not need to implement parsing manually and less chances of mistakes in implementing parsing, like you may make a mistake in mentioning key "Success" or "success" or any such silly mistakes!
Firstly, since your variable is static, and the methods are static too, you don't have to instantiate the object. You could do something like this:
ArrayClass.add_val("Hello");
But if you want to instantiate then you can do this:
public class ArrayClass {
private ArrayList<String> array;
public ArrayClass() {
array = new ArrayList<>();
}
public void add_val(String s){
array.add(s);
}
public int get_size(){
return array.size();
}
public String get_val(int i){
return array.get(i);
}
}
To make sure the values are filled in, you can check the array size like this:
for (l=0;l<length4;l++){
filled = jsonResponse4.getString(l+"");
fill.add_val(filled);
}
Log.d("TEST", String.valueOf(fill.get_size());
Remove all cases of the static keyword in ArrayClass. Static methods are class level methods, ie. are called on the class itself, rather than an instance of the class.
You can also try this, for ArrayList:
First do some changes in your ArrayClass. Use get And Set method to access your array.
public class ArrayClass {
private ArrayList<String> array = new ArrayList<>();
public ArrayList<String> getArray() {
return array;
}
public void setArray(ArrayList<String> array) {
this.array = array;
}
}
And your other class where you attempt to edit the ArrayList use getArray And SetArray method and some predefined method of ArrayList like this:
Store the data in ArrayList:
for (l=0;l<length4;l++){
filled = jsonResponse4.getString(l+"");
fill.getArray().add(filled);
}
Get Size of ArrayList:
fill.getArray().size();
And also you can store an another ArrayList like
ArrayList<String> tempArrayList = new ArrayList<String>();
tempArrayList.add("string 1");
tempArrayList.add("string 2");
tempArrayList.add("string 3");
tempArrayList.add("string 4");
fill.setArray(tempArrayList)
I've got a method called removeSup which is supposed to remove an object Supplement from a list of supplements.
this is the code for the method:
private static void removeSup(Supplement supToRemove, List<Supplement> listToRemoveFrom) {
Iterator<Supplement> iterator = listToRemoveFrom.iterator();
while(iterator.hasNext()){
if(iterator.next().equals(supToRemove)){
iterator.remove();
}
}
}
there is a class called magazine which defines the list of supplements.
public class Magazine {
private List<Supplement> supList;
public List<Supplement> getSupList() {
return this.supList;
}
public void setSupList(List<Supplement> supList) {
this.supList = supList;
}
public Magazine(Double cost, String _name){
this.supList = new ArrayList<>();
this.weekCost = cost;
this.name = _name;
}
}
the class supplement has the following constructor
public Supplement(String _name, Double _price, String _magName ){
this.name=_name;
this.price=_price;
this.magName = _magName;
}
in the main class client there is a search that the user can do to remove a certain Supplement
private static void searchSup(){
System.out.println("Search for Supplement");
String search = scanner.nextLine();
for (Supplement sup : magazine.getSupList()) {
if (!sup.getSupName().equalsIgnoreCase(search)) {
//do something
}
else{
removeSup(sup,magazine.getSupList());
}
}
}
the main method in the client class is as follows:
private Magazine magazine;
public static void main(String[] args) {
magazine = new Magazine(3.0, "pop");
List<Supplement> startList = new ArrayList<>();
startList.add(new Supplement("Nat Geo", 3.0,"pop"));
startList.add(new Supplement("Discovery", 5.0,"pop"));
startList.add(new Supplement("Health", 6.3,"pop"));
startList.add(new Supplement("IT", 8.3,"pop"));
magazine.setSupList(startList);
searchSup();
}
When I run this program and type any of the added supplements, i get an error
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
at java.util.ArrayList$Itr.next(ArrayList.java:831)
at Client.searchSup(Client.java:131)
at Client.searchSup(Client.java:140)
at Client.main(Client.java:588)
is it the for loop i am using to search giving me an error? if so how would i go about fixing this?
You generally shouldn't modify a Collection while iterating over it. It's fine to modify elements, but you really shouldn't remove something from a Collection while iterating. See here: http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html. Also, the Javadoc for ConcurrentModificationException may be helpful.
You might try returning a new list with the Supplement removed:
private static List<Supplement> removeSup(Supplement supToRemove, List<Supplement> listToRemoveFrom) {
List<Supplement> filteredSupplements = new ArrayList<Supplement>();
for(Supplement supplement : listToRemoveFrom) {
if(!suppplement.equals(supToRemove)){
filteredSupplements.add(supplement);
}
}
return filteredSupplements;
}
It seams that the "magazine" is local var in the method of main, not accessible to searchSup.Fix it like
private void searchSup(Magazine magazine)
{
//...
}
and more details if you can provide, the codes in Line 131 and 140 will be helpful.
I figured out that the search i was doing was not working with what i wanted to do so i created a method which returns an integer of the Supplement in the list.
private static int indexOfSup(List<Supplement> supSearchList, String nameOfSup) {
for (Supplement sup : supSearchList) {
if (sup.getSupName().equalsIgnoreCase(nameOfSup)) {
return supSearchList.indexOf(sup);
}
}
return -1;
}
i then use this integer to remove from the list.
a simple List.Remove(index) worked fine
Thanks for all the replies.
I have a question on copy construction in Java. Consider the following class;
In the copy constructor I can say new(Integer(other.id)) to get a new integer object being passed to the constructor, but I can't say new T(other.data) as the compiler will say cannot instantiate the type T. How can I make sure that when the generic item is copy constructed that it will not just pass a reference such that the 2 objects will share the underlying data.
Also, in the getLinks method it is doing a new and creating a new object of the list but is that going to deep copy and create new object of the items contained in the list or will it just contain references to the existing objects list items such that you have 2 lists both pointing to the same data. See below the comments / code. Thanks in advance for your expertise.
class DigraphNode<T>
{
Integer id;
T data;
ArrayList<DigraphNode<T> > links;
public DigraphNode(Integer i)
{
id = i;
links = new ArrayList<DigraphNode<T> >();
}
public DigraphNode(Integer i, T d)
{
id = i; data = d;
links = new ArrayList<DigraphNode<T> >();
}
public DigraphNode(DigraphNode<T> other)
{
other.id = new Integer(other.id);
other.data = other.data; // line in question
this.links=other.getLinks(); // also will create a new list with references
// or will it deep copy the items contained in the list?
// see getLinks() method below
}
public void setData (T d ) { data = d; }
public void addLink (DigraphNode<T> n) { links.add(n); }
public void addLinks (ArrayList<DigraphNode<T> > ns) { links.addAll(ns); }
public ArrayList<DigraphNode<T> > getLinks()
{
return new ArrayList<DigraphNode<T> >(links);
}
public void printNode()
{
System.out.print("Id: " + id + " links: ");
for ( DigraphNode<T> i : links )
{
System.out.print(i.id + " ");
}
System.out.println();
}
}
You can't instantiate new T(other.data) as you tried, but you can clone() other.data if T implements Cloneable
Every call to getLinks() will create a new list with reference to object contained to links, you have to different lists with same reference inside (so change one reference object property will reflect to other list object because they are the same object)
About ArrayList<> links = new ArrayList<>(); from Oracle doc:
Initializer blocks for instance variables look just like static
initializer blocks, but without the static keyword:
{
// whatever code is needed for initialization goes here
}
The Java compiler copies initializer blocks into every constructor. Therefore, this approach can be used to share a block of
code between multiple constructors.
EDIT:
You can define a static method (copy) that try to use all possible strategies to copy generic object; the best approch is to define your own interface to separate your own stategy and simulate a sort of copy-constructor (you can reuse copy method if you want), else via serialization or, as last try, using cloning (but clone() is full of pitfall).
You can also use this libraries:
Cloning
Commons-SerializationUtils
interface MyCloneableInterface<T> {
T duplicate(T object) throws CopyException;
}
public static <T> T copy(T data) throws CopyException {
if(data == null) return null;
if(data instanceof MyCloneableInterface) {
return ((MyCloneabeInterface)data).duplicate(data);
}
if(data instanceof Serializable) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return (CloneExample) ois.readObject();
}
catch(...) {//rethrow}
}
if(data instanceof Cloneable) {
try {
return (T)data.clone();
}
catch(CloneNotSupportedException e) {//rethrow}
}
// else you can look for copy-constructor via reflection or
// cloning object field-by-field via reflection...
}
First Question: You cannot instantiate a generic instance (in other words call T's constructor). You should either define T implements Cloneable and call clone or use another interface of your own if T is always under your control. There are many pitfalls to this method, I'd suggest you first read about this interface and familiarize yourself with the pitfalls (you can find a great chapter on this, in "Effective Java" book). Also, it is not always that you can guarantee that this class will use T types which are Cloneable.
About links - you're instantiating it in the beginning and then override it in the constructor - Why? Remove the initialization. The way your getLinks works is not by creating a deep copy. Meaning - you'll get a new list, the list itself will be different from the original list, but the items will be shallow copies.
About your last question - as I already said, it's redundant. Remove the initialization at the beginning. You're creating an object, never use it and leave it for garbage collection. What you can do to avoid calling this in every constructor is something like this:
public DigraphNode() {
links = new ArrayList<DigraphNode<T> >();
}
And have other constructors call this constructor, for example:
public DigraphNode(T val) {
this();
this.data = val;
}
Upvoted all helpful answers, but I am answering my own question below which shows the updated code. I wanted to see how someone would implement a copy for a generic but no one posted code for that so I rolled my own. See below my answer.
import java.lang.reflect.*;
import java.util.*;
class MissingDigraphNodeException extends Exception
{
private static final long serialVersionUID = 1000L;
public MissingDigraphNodeException(String message)
{
super(message);
}
}
class CopyException extends Exception
{
private static final long serialVersionUID = 2000L;
public CopyException(String message)
{
super(message);
}
}
class DigraphNode<T>
{
Integer id;
T data;
ArrayList<DigraphNode<T> > links;
public DigraphNode(Integer i)
{
id = i;
links = new ArrayList<DigraphNode<T> >();
}
public DigraphNode(Integer i, T d)
{
id = i; data = d;
links = new ArrayList<DigraphNode<T> >();
}
public DigraphNode(DigraphNode<T> other)
{
try
{
this.data = copy(other.data);
}
catch (CopyException e)
{
e.printStackTrace();
}
this.links=other.getLinks();
this.id = new Integer(other.id);
}
// is there a better way to copy a generic?
#SuppressWarnings("unchecked")
public T copy( T source ) throws CopyException
{
Class<?> clzz = source.getClass();
Method meth;
Object dupl = null;
try {
meth = clzz.getMethod("clone", new Class[0]);
dupl = meth.invoke(source, new Object[0]);
} catch (Exception e)
{
e.printStackTrace();
throw new CopyException("Error: Copying Generic of T");
}
return (T) dupl;
}
public void setData (T d ) { data = d; }
public void addLink (DigraphNode<T> n) { links.add(n); }
public void addLinks (ArrayList<DigraphNode<T> > ns) { links.addAll(ns); }
public ArrayList<DigraphNode<T> > getLinks()
{
// return a new copy of the list
ArrayList<DigraphNode<T> > l = new ArrayList<DigraphNode<T> >();
for ( DigraphNode<T> i : links )
{
i.links.add(new DigraphNode<T>(i)); // use copy constructor
}
return l;
}
public void printNode()
{
System.out.print("Id: " + id + " links: ");
for ( DigraphNode<T> i : links )
{
System.out.print(i.id + " ");
}
System.out.println();
}
}