Replace one field with another in a method - java

I'm trying to dynamically replace in a method body a field reference by another field reference. is that possible with bytebuddy?
The class I like to transform is like this:
public class TestReplace {
#replace
int a = 1;
int b = 2;
public int printA() {
return a;
}
public int printB() {
return b;
}
}
The transformation consists in replacing the variables marked with #replace in the methods that visit them. The replacement will be done by variables that I will insert.
The class already transformed should look like this:
public class TestReplace {
#replace
int a = 1;
int ___a = a * 10; // var inserted
int b = 2;
public int printA() {
return ___a;
}
public int printB() {
return b;
}
}
I am new to the subject and would appreciate any help you could give me.
Thanks in advance

Yes, this is possible using MemberSubstitution:
MemberSubstitution.relaxed()
.field(ElementMatchers.named("a"))
.onRead()
.doReplaceWith(otherField)
You can, for example, apply this transformation from a Java agent that you define using the AgentBuilder API. You probably also need to define the alternative field from this agent. You can reference this field using a FieldDescription.Latent.

Related

Class scope variabile visibility

If I have:
class A
{
void foo()
{
int a = count;
}
void bar()
{
int a = c; // here ERROR
int c = 10;
}
private int count = 10;
}
here in foo count is used without problem also if it's declared after the use.
The same is not true in method bar where the variable c must be declared before its
use.
Which are the class scope rules? How they differs from method scope rules?
P.S.
My doubt is because the common scope resolutions rules:
When the compiler find count it should try to find it "back" to its
use but back there is Class A... so maybe private int count is "hoisting" at
beginning of Class A?
Imagine that you were a compiler, and you get to the line:
int a = c;
Won't you get angry and ask yourself "What is c"? The order is important1.
1count doesn't make a problem because it's a class member, it's known in the whole class. You can place class members in the beginning of the class, or at the end.
count is declared in the class while c is declared in the method
While compiling, the class would find count in the class.
class A
{
void foo()
{
int a = count;
}
private int count = 10;
}
is equal to put count anywhere in the class, as it is a class member and can be found in the class everywhere.
while in your case of
class A
{
void bar()
{
int a = c; // here ERROR
int c = 10;
}
}
c is not defined before use, as c is a local variable in a method.

Instantiation and declaration separate

My question is regarding the declaration and value assignment rules in Java.
When writing the fields we can declare and assign values together but we cannot do the same separately.
E.G.:
class TestClass1 {
private int a = 1;
private int b ;
b= 1;
private int sum;
public int getA() {
return a;
}
public int getB() {
return b;
}
public int getSum() {
sum = a + b;
return sum;
}
}
public class TestClass {
public static void main(String[] args) {
TestClass1 testClass1 = new TestClass1();
System.out.println("total =" + testClass1.getSum());
}
}
Here in line:
private int a = 1;
We are able to declare a as a private int and assign a value 1 to it. But in case of:
private int b ;
b= 1;
Eclipse does not allow this to happen and throws an error. Kindly explain the logic behind this.
Code inside a class, but outside a function, is purely declarations. It does not get "executed". It simply declares what fields a class contains.
The reason you can do the shorthand private int a = 1; is just syntactic sugar that the Java language allows. In reality, what happens is that the a = 1 part is executed as part of the constructor. It's just easier to read and write when it is next to the variable declaration.
It's something nice that the Java langage creators allowed. Not every language allows that, look at C++ as an example that does not always allow it.
you have to put b=1; inside a method or put this inside a constructor.
you are getting this error since you can't do any thing other than declaration(private int a= 1;
) in class level.
It's just a question of syntax in Java. In the example you show, you try to affect a value to b in the member declaration part of your class. This is not allowed by the syntax of Java. You can only do it when you declare your attribute, in the body of a method or in a static block if your attribute is static e.g. :
private static int b;
static {
b = 1;
}
It is only a syntax problem. You can do it like this :
private int b ;
{ // <- Initialization block
b= 1;
}
See What is an initialization block?
You are unable to write logic directly in the class. You should move it to the constructor.
Java only allow declaration within the class and outside any method. Declarations like int b = 1; will be executed when you initialize a new Object.

How to return multiple values from a function.

This is more of a logical question than code specific, I have some twenty functions, each function calculates two values of my interest. However I can only return one value from a function. Now the other option I have is to make a class and implement setter and getter with global variables. I want to know if this is a feasible and recommended way? Or there is a better way to do this?
Don't use global variables! Use some class that has your data as private fileds, and provide getters for it. Like in
class Pair<A,B> {
final A one;
final B two;
public Pair(A fst, B snd) { one = fst; two = snd; }
public A getFst() { return one; }
public B getSnd() { return two; }
}
Then you can elsewhere say something like:
return new Pair(42, "a result");
Return a Collection from your function containing your values of interest.
Depends on the problem. But 2 solutions are :
Make new class which instances will be returned by all this functions. This class would have 2 attributes for each needed answer.
Return array or Collection with this 2 answers.
You have to return a List or a array.
But if return types are different you can create custom class and use it as return type.
Example
public class Result {
private String name;
private int age;
// getters and setters;
}
Now you can have some thing like following
public static Result getInfo(){
Result result=new Result();
result.setName("name");
result.setAge(10);
return result;//now you can have String and int values return from the method
}
There are many ways: collections, arrays ...
In my opinion the only way is to define a class with these values.
you do not need getter and setter methods if you don't need to regulate the visibility of the contents
class MyReturnValue {
public int a;
public int b;
}
in your code:
...
MyReturnValue result=new MyReturnValue();
result.a=5;
result.b=6;
return result;
It is better to make a class and implement setter and getter with global variables rather than to Return Collection further it depends on your use.
You can do this
long[] function() {
long[] ret = { a, b };
return ret;
}
or
long[] a = { 0 }, b = { 0 };
void function(long[] a, long[] b) {
a[0] = ...
b[0] = ...
or add properties to an object.
private long a,b;
void function() {
a = ...
b = ...
}
in the last case you can value.
class Results {
public final long a;
public final Date b; // note: Date is not immutable.
// add constructor
}
public Results function() {
long a = ...
Date b = ...
return new Results(a, b);
}
I think making a Record class is the most suitable.
public class Record {
public final int a;
public final int b;
public Record(final int a, final int b) {
this.a = a;
this.b = b;
}
}
Then your functions can return type Record, and you can access it with let's say record.a and record.b.
This is also one of the few cases where public variables and no getters and setters can be justified.
UPDATE: Implemented a proposed change, now everything is final, which means that Record cannot be modified when you get it back, which seems to be in line with expectations. You only want the results and use those.
What about adopting varargs with generic helper function for getting around of number of returning variable limitation: In this solution, we won't have to declare a new class every time when number of returning variable changes.
class Results
{
private final Object[] returnedObj;
public Results(Object... returnedObj)
{
this.returnedObj = returnedObj;
}
public <E> E getResult(int index)
{
return (E)returnedObj[index];
}
}
Test case:
public static Results Test()
{
return new Results(12, "ABCD EFG", 12.45);
// or return larger number of value
}
//// And then returning the result
Results result = Test();
String x = result.<String>getResult(1);
System.out.println(x); // prints "ABCD EFG"
You could even return the values separated by a special character say a "~" if you are sure that the "~" won't appear in your results.

Is there a way to pass a value to a specific item in a constructor?

I'm sorry if this is a very basic but I couldn't find anything in my books and searching. I am trying to send information when creating an object but there's many options and I only really to change one(unfortunately, its near the end).
Say I have something like this:
class_to_start_(int maxActive,
byte whenExhaustedAction,
long maxWait,
int maxIdle,
int minIdle,
boolean testOnBorrow,
boolean testOnReturn,
long timeBetweenEvictionRunsMillis,
int numTestsPerEvictionRun,
long minEvictableIdleTimeMillis,
boolean testWhileIdle,
long softMinEvictableIdleTimeMillis,
boolean lifo)
They all have default values so I don't need to change any of them, but I want to modify the default value of the last one lifo only. Can I do it without sending values to all others? Ideally something like class_to_start_('lifo'=True) (this doesn't work, I tried it).
Is this possible?
Java doesn't have default parameter values, so the short answer is no.
You can have overloaded constructors however, so that you have a constructor that just takes the argument you want to change:
/** Main constructor. */
public Foo(int maxActive,
byte whenExhaustedAction,
int minIdle,
boolean testOnBorrow,
boolean lifo)
/** Convenience constructor. */
public Foo(boolean lifo)
{
this(1, 0x01, 3, false, lifo); // call the main constructor will default values
}
You could also look at making a fluent interface builder object. The idea then would be you do:
final Foo f = new FooBuilder().withLifo(false).build();
You can add a constructor that takes a Map of parameter and value pairs, and use the defaults for any parameters not specified. That way you only need to specify the parameters you want to override.
What also could work is to create one instance of your desired class and set all values to your desired default values:
// in your main method
Foo myDefaults = new Foo(100, "name", false, true);
myDefaults.setLifo(false);
Foo someChangedInstance = myDefaults;
...then add a constructor to your class that takes an instance of the class and sets all values equal to the values of the parametered instance:
// in your Foo class
public Foo(int maxWidth, String standardName, boolean logEverything, boolean lifo) {
// ...
}
public Foo(Foo otherInstance) {
this.maxWidth = otherInstance.maxWidth;
this.standardName = otherInstance.standardName;
this.logEverything = otherInstance.logEverything;
this.lifo = otherInstance.lifo;
}
That way you can modify only single values of the instance of your class and create new instances with only some modifications.
Don't forget to probably reset the attributes in myDefault after changing them.
myDefault.setLifo(true);
When the default values are typically used, and there are a lot of parameters, using a constructor or a factory method becomes clumsy. The most convenient and elegant approach is to use setters with a fluent interface.
Like this:
public class MyClass {
// Define default values in initializers
private int maxActive = 5;
private byte whenExhaustedAction = 'x';
private long maxWait = 999;
private int maxIdle = 3;
private int minIdle = 1;
private boolean testOnBorrow = true;
private boolean testOnReturn = false;
private long timeBetweenEvictionRunsMillis = 5000;
private int numTestsPerEvictionRun = 10;
private long minEvictableIdleTimeMillis = 2000;
private boolean testWhileIdle = false;
private long softMinEvictableIdleTimeMillis = 0;
private boolean lifo = true;
// Only getter/setters for first two fields shown - others similar
public int getMaxActive() {
return maxActive;
}
// Return "this" to create a fluent interface
public MyClass setMaxActive(int maxActive) {
this.maxActive = maxActive;
return this;
}
public int getMaxIdle() {
return maxIdle;
}
public MyClass setMaxIdle(int maxIdle) {
this.maxIdle = maxIdle;
return this;
}
// Other getters/setters to follow
}
Use it like this, only calling the setters of the fields where you want a value other than the default:
MyClass x = new MyClass().setMaxActive(5).setMaxIdle(100);

Java: Modifying variables without arguments

I'm just beginning to learn Java and I have been very frustrated about learning Java's scope rules. You see I wish to create a Method without the use of arguments/parameters.
In JavaScript, I can do this with ease using functions:
/** Function to increase 2 vars.
/** **/
function modifyNow(){
a++;
b++;
} // END
var a = 5;
var b = 10;
modifyNow();
// By this part, a and b would be 6 and 11, respectively.
Now this is saving me a lot time and simple since whenever the function is called, var a and b, already exist.
So, is there a way to do this in Java without having arguments like how I do it in JavaScript? Or is there another way around this?
Thank you, appreciate the help... ^^
What is the problem with having a and b as private variables in your class, and increment them in modifyNow()? And by the way everything in Java must be in a class. You can't have global code mangling around...
You can do this for class fields, not for local variables.
class Clazz {
int a = 5;
int b = 10;
public void modifyNow() {
a++;
b++;
}
}
// ...
Clazz c = new Clazz();
c.modifyNow();
Now, after each call to modifyNow, the fields are updated.
Global variables are bad. Without knowing your intent, I would say you need to add the variables as members to your class. They are accessible then from any member function.
You see I wish to create a Method without the use of
arguments/parameters.
The best answer is: don't!
If you nevertheless want this, look for public static variables.
class Foo {
int a = 5;
int b = 10;
public void modifyNow(){
a++;
b++;
}
}
You need to use what are called member variables, they are tied to an instance of your class.
public class MyClass
{
// these are Class variables, they are tied to the Class
// and shared by all instances of the class.
// They are referenced like MyClass.X
// By convention all static variables are all UPPER_CASE
private static int X;
private static int Y
// these are instance variables that are tied to
// instances of the class
private int a;
private int b;
/** this the default no arg constructor */
public MyClass() { this.a = 5; this.b = 10; }
/** this is a Constructor that lets you set the starting values
for each instance */
public MyClass(final int a, final int b) { this.a = a; this.b = b; }
public modifyNow() { this.a++; this.b++; }
/** this is an accessor to retrieve the value of a */
public int getA() { return this.a; }
public int getB() { return this.b; }
}
final MyClass myInstanceA = new MyClass();
myInstance.modifyNow();
// a = 6, b = 11
final MyClass myInstanceB = new MyClass(1, 2);
myInstance.modifyNow();
// a = 2, b = 3
Everytime you do a new MyClass() you will get a new independent instance of MyClass that is different from every other instance.
As you are learning JavaScript is not related to Java in anyway. It is a terrible travesty that they picked that name for marketing reasons.

Categories