Abnormal behavior while using proguard - java

My Original code is :
private String hello;
private int i = 0;
public void test() {
if (i == 0) {
hello = "asdas";
} else {
hello = "asasvfasfas";
}
}
After Obfuscating with proguard :
private String a;
private int c = 0;
public void a()
{
if (this.c == 0);
for (this.a = "asdas"; ; this.a = "asasvfasfas")
return;
}
In project properties :
proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
My proguard-project.txt file is empty, so I guess it should be using the default config file : proguard-android.txt.
Why it is behaving like this? How can I prevent this kind of code optimization? Please help.

Because your code is only that fragment you entered, I assume, your code will be easily optimized into this:
private String hello;
public void test() {
hello = "asdas";
}
The Proguard just doesn't remove your original but unreachable source lines, just puts them into unreachable places. It is converting your code into equivalent but not-so human friendly format.
So, the generated code works as yours, it is just obfuscated. If you don't like it, don't use obfuscators.

Related

java getting concept of OOP right

hi guys I already searched a lot but weren't really satisfied with what I found. hope it's the right place to ask this question.
I'm doing Java now for a small amount of time (changed from C) and have problems of getting a grip of how to structure my code best for OOP.
let's give a simple example:
If I'm using some predefined strings (let's say e.g. filepaths or error messages) I'm currently creating an own class doing something like:
private static final String libPath = "\\this\\is\\a\\path\\";
private static final String notFoundMessage = "This hasn't been found";
public static String getLibPath() {
return libPath;
}
public static final String getNotFoundMessage() {
return notFoundMessage;
}
...
Would it be better to create a Map, add everything to it and get it by key?
Or am I doing it completely wrong?
Second example:
let's say I return an error string somewhere
public String getSomething() {
if (something != null) {
return something;
} else {
//handle error, return string below
}
return "I HAVE AN ERROR";
}
And anywhere else in my program I'm checking for the return value:
if (!string.equals("I HAVE AN ERROR")) {
//do something
}
else {
// handle error
}
that's obviously a bad way having to change the code twice once the error message changes. and yeah, I could define the error string the same way I'm doing it in the first example but as I'm not satisfied with that one either I'm reaching a dead end.
would be glad to hear some of your suggestions how to properly do OOP !
First example :
private static final String libPath = "\\this\\is\\a\\path\\";
private static final String notFoundMessage = "This hasn't been found";
public static String getLibPath() {
return libPath;
}
public static final String getNotFoundMessage() {
return notFoundMessage;
}
...
In this case, no need to create a Map. That is the right way to do it. Just note that the libPath would be better defined like this :
private static final Path libPath = Paths.get("this", "is", "a", "path");
(The class Path exists since Java 7, current version is Java 8)
Second example:
public String getSomething() {
if (something != null) {
return something;
} else {
//handle error, return string below
}
return "I HAVE AN ERROR";
}
No : Never return error codes in Java. Prefer using an exception.
Example :
public class ElementNotFoundException extends Exception {
...
}
public String getSomething() {
if (something == null) {
throw new ElementNotFoundException();
} else {
return something;
}
}
Then, you handle the exception like this :
try {
myObject.getSomething();
} catch(ElementNotFoundException e) {
//handle error
}
For the first example, take a look at Internationalization: http://docs.oracle.com/javase/tutorial/i18n/
You can use statics or maps, but sooner or later you will need to show the messages in several languages.
For the second example, it's better to use Exceptions as they are intended to be used when an abnormal condition (like an error) happens.
Anyway, with Exceptions take care not to use it as flow control structures: Why not use exceptions as regular flow of control?
Here are some examples for handling constants throug out your code:
1. Class
public final class MyConstants {
public static final int ERROR_CODE = -1;
}
if (getSomething() == MyConstants.ERROR_CODE) {
// ...
}
2. Interface
public interface MyConstantsHolder {
int ERROR_CODE = -1;
}
public MyClass implements MyConstantsHolder {
public void myMethod() {
if (getSomething() == ERROR_CODE) {
// ...
}
}
}

Failure: org.junit.ComparisonFailure: File testfile_1.txt Line 1

Its me again...with the same context. I ran a test file in Dr.Java for my constructor. It is about reading a file in the directory to test. Here is part of content in test file:
public void cw_println_file1 () throws Exception {
String actual, msg, expect;
String filename;
CensoredWriter out;
for(int i=0; i<fileLines.length; i++){
String [][] test = fileLines[i];
String censor = test[0][0];
String [] outLines = test[1];
String [] expectLines = test[2];
filename = String.format("testfile_%d.txt",i);
out = new CensoredWriter(filename,censor);
for(int j=0; j<outLines.length; j++) {
out.println(outLines[j]);
}
out.close();
assertLines(expectLines, filename);
}
}
I got an error message like this:
File: C:\Users\jiangbuyun\Desktop\lab5\distrib-lab05\Lab05Tests.java [line: 137]
Failure: org.junit.ComparisonFailure: File testfile_1.txt Line 1
Expect: A %!^##er-scooper, or %!^## scoop, is a device used to pick up animal
Actual: A %!^##er-scooper, or %!^## scoop, is a device used to pick up animalfeces from public places and yards, particularly those ofdogs. %!^*##er-scooper devices often have a bag or bag attachment.
Expected:<...ed to pick up animal[]>
but was:<...ed to pick up animal[feces from public places and yards, particularly those ofdogs. %!^*##er-scooper devices often have a bag or bag attachment.]
I found it is supposed to stop at the brackets after "animal" and nothing is between the two brackets, but it actually continued to read text and put it into the brackets.
public class CensoredWriter extends PrintWriter {
String censored;
public CensoredWriter(OutputStream o, String c) {
super(o);
this.censored = c;
}
public CensoredWriter(File f, String c) throws Exception {
super(f);
this.censored = c;
}
public CensoredWriter(String s, String c) throws Exception {
super(s);
this.censored = c;
}
public String transform(String s) {
String a = s.replaceAll(censored, "%!^*##");
return a;
}
#Override
public void print(String s) {
super.print(transform(s));
}
#Override
public void println(String s) {
print(s);
flush();
}
}
From what you posted, the issue is that you seem to replace censored with "%!^*##", so that part of the implementation works. However, stopping after animal is the part you haven't implemented yet.
By the way, when asking questions, try to provide the necessary context. For example, I suppose your method cw_println_file1 is a test (#Test) method -- it would help to see that without guessing. Also, if your method requires some stuff from a #Before method (eg. fileLines seems to be declared somewhere else), it might help for the reader to understand your problem to see those required parts as well.

How to return String in anonymous class for a method returning void

I'm bit confused. I have the following:
public static String showInputDialog() {
Form frm = new Form();
final Command cmd = new Command("Ok");
final TextField txt = new TextField("Enter the text", null, 1024, 0);
frm.addCommand(cmd);
frm.append(txt);
frm.setCommandListener(new CommandListener() {
public void commandAction(Command c, Displayable d) {
if (c == cmd) {
return txt.getString(); // Error !!
} else {
return null; // Error !!
}
}
});
}
As you can see, I want to return the input dialog string, while the anonymous class method should return void. How can I resolve this problem?
This does not work as you expected.
I see there are already some solutions, but I feel a bit more discussion about what is actually going on might be helpful.
When you call the frm.setCommandListener(new CommandListener() { ... }) the code presents the user with a dialog where she can type in some text and submit, but the code does not stop and wait until the user finishes.
Instead the code continues to execute - without yielding the result. Only after the user finished typing and submits, you get called back to process the result - which might happen much later, or not at all.
I guess you have some code calling this method like:
public void someMethod(int foo, String bar) {
[...]
String result = MyInputForm.showInputDialog();
// do something with the result
System.out.println("hey, got a result "+ result);
[...]
}
Instead you need to reorganize this. First write a helper class handling the result:
public static class MyCallBack {
public MyCallBack(... /* here pass in what you need to process the result*/) {
... remember necessary stuff in instance variables
}
public void processResult(String result) {
// do something with the result
System.out.println("hey, got a result "+ result);
[...]
}
}
then the calling side does just:
public void someMethod(int foo, String bar) {
[...]
MyInputForm.showInputDialog( new MyCallBack(... here pass in stuff ...) );
[...]
}
and the actual code has to be changed to:
public static String showInputDialog(final MyCallBack callback) {
Form frm = new Form();
final Command cmd = new Command("Ok");
final TextField txt = new TextField("Enter the text", null, 1024, 0);
frm.addCommand(cmd);
frm.append(txt);
frm.setCommandListener(new CommandListener() {
public void commandAction(Command c, Displayable d) {
if (c == cmd) {
return callback.processResult(txt.getString());
} else {
return; // or just omit the else part
}
}
});
}
Two issues:
this way of programming feels pretty backwards, but it is really the way it works.
what feels not right is that I need to define a second helper class aside of the CommandListener. That is really not good style. I hope it can be improved, but as I do not see the complete code (which would be too much information anyway), I have to leave it to you to improve the code and get rid of the clutter. While I feel you want to have a modular, reusable input dialog helper, this might not be the best approach; better define the Form,TextField and Command directly where you need the result and get that running. Make it reusable in a second step after you get it running.
You don't need to return it if you instead do something with the String or store it somewhere, for example:
static String result;
public String commandAction(Command c, Displayable d) {
if (c == cmd) {
result = txt.getString();
} else {
result = null;
}
}
Although you'll have threading issues to deal with.
Given that CommandListener is fixed, 2 possible options are
Use a class member variable in the outer class & assign to that variable instead
private static String myText;
...
public static String showInputDialog() {
...
frm.setCommandListener(new CommandListener() {
public void commandAction(Command c, Displayable d) {
if (c == cmd) {
myText = txt.getString();
} else {
myText = null;
}
}
});
}
or Create a concrete implementation of your CommandListener and set the return value as a property of the new implementation
I would have a look at making the method/variable in this snippet non-static...
You cant return the string because you dont know when the listener will be called.
You can do something with it once you have the string though.
public static void showInputDialog() {
StringHandler sh = new StringHandler();
frm.setCommandListener(new CommandListener() {
public void commandAction(Command c, Displayable d) {
if (c == cmd) {
sh.handle(txt.getString());
} else {
sh.handle(null);
}
}
});}
public class StringHandler {
public void handle(String s){
// Do something with that string.
}
}

Better way to map from String constants to int constants in Java

I have a load of images of musical symbols which I need to do some processing on and for each one I need to get the integer code corresponding to its file name. There are 23 possible file name strings and 23 integer code and there are many images with the same name under different directories.
The solution I have so far is given (abbreviated) below. I have just defined a load of int and String constants and then written a method which is just a huge chain of if statements to do the translation.
What would be a better way to achieve the same effect? The way I've done it seems really awful! I thought about using some kind of Map, but I wasn't sure of the best way to do so.
public class Symbol {
public static final int TREBLE_CLEF = 0;
public static final int BASS_CLEF = 1;
public static final int SEMIBREVE = 2;
// ...
public static final String S_TREBLE_CLEF = "treble-clef";
public static final String S_BASS_CLEF = "bass-clef";
public static final String S_SEMIBREVE = "semibreve";
// ...
public static int stringCodeToIntCode(String strCode) {
if (strCode == S_TREBLE_CLEF) {
return TREBLE_CLEF;
} else if (strCode == S_BASS_CLEF) {
return BASS_CLEF;
} else if (strCode == S_SEMIBREVE) {
return SEMIBREVE;
} //...
else {
return -1;
}
}
}
I think you are looking for Enum where you can have String constant and its value.
Example:
public enum YourEnumClass{
STRING_CONST (5),
STRING_CONST2 (7),
.....
//constructor
//getValue() method
}
read linked tutorial for more details.
enum StringToInt{
TREBLE_CLEF(0),
......
}
Enum is the way to go.
Another example:
public enum Color {
WHITE(21), BLACK(22), RED(23), YELLOW(24), BLUE(25);
private int code;
private Color(int c) {
code = c;
}
public int getCode() {
return code;
}
how about a hashmap
HashMap<String,Integer> hm=new HashMap<String,Integer();
hm.put("treble-clef",0);
//rest
and get it by using this
int value=hm.get("treble-clef");

How to avoid forgetting to process properties?

Having this class
Class Test
{
static int version=1;
String A;
String B;
//constructor
//setters, getters, etc...
public void printAll(void)
{
System.out.println(A);
System.out.println(B);
}
}
After a while, we modify the Class to add a String C :
Class Test
{
static int version=2;
String A;
String B;
String C;
//constructor
//setters, getters, etc...
public void printAll(void)
{
System.out.println(A);
System.out.println(B);
//it seems somebody has forgotten to print C!!!!!!!!!
}
}
Is here some known approach to avoid this kind of bug?
Thanks
A code review should catch this issue. Aside from a code review, unit testing or debugging would normally tell you if your code is behaving how it should. If you didn't process certain properties your tests should fail because at some point a method/property/result would not be correct. Other than those things I think using reflection is way overboard.
You can use annotations to have a more structured way to use reflection, where you better control which fields will be printable:
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.FIELD})
#interface Printable { }
class Test {
#Printable String A;
#Printable String B;
#Printable String C;
public void printAll() {
for (Field field : getClass().getDeclaredFields()) {
if (field.isAnnotationPresent(Printable.class)) {
try {
System.out.println(field.get(this));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
}
I'm not sure if it's recommended, but you could get the fields of an object in the following way:
import java.lang.reflect.Field;
Field[] fields = object.getClass().getDeclaredFields();
for (int i = 0 ; i < fields.length ; i++)
System.out.println(fields[i]);
You have some code that adding, deleting or modifying in a place, affects in other. In this particular case, your function calls all properties.
You may want to something like C++, where classes doesn't have explicit properties like Java, and are emulated using either a macro or a collection.
package mycompany.myapp;
import propertiesgenerics;
Class Test
{
static int version=1;
public property<String> A;
public property<String> B;
public list< property<string> > Properties;
public Bicycle() {
public property<String> A = new property<String>();
public property<String> B = new property<String>();
Properties.add(A);
Properties.add(B);
}
//constructor
//setters, getters, etc...
public void printAll(void)
{
// iterating thru this.properties
for loop {
System.out.println(eachProperty);
} // for loop
}
}
If not a fan of misusing reflection, due to the fact that not all fields are treated like properties, and not all properties are treated like fields.
You can use org.apache.commons.lang.builder.ToStringBuilder:
public void printAll() {
System.out.println(ToStringBuilder.reflectionToString(this));
}
or
public void printAll() {
System.out.println(new ToStringBuilder(this).
append("name", name).
append("age", age).
append("smoker", smoker).
toString());
}
Sometimes the best strategy is just to put comments above your property list:
// Remember to include any new properties in the printAll method!
String A;
String B;
Apart from that, I agree with KyleM, that a code review is essential for catching issues like this.
I'm not sure I'd qualify forgetfulness as a bug. I think the best way to handle something like this is to use a source control program, so you can track changes to your files.
http://tortoisesvn.net/: this is a good one

Categories