Reflection: Why are there methods like setAccessible()? - java

Just wondering, why did the people who invented Java write methods like setAccessible(boolean flag), which makes the access-modifiers (specially private) useless and cannot protect fields, methods, and constructors from being reached? Look at the following simple example:
public class BankAccount
{
private double balance = 100.0;
public boolean withdrawCash(double cash)
{
if(cash <= balance)
{
balance -= cash;
System.out.println("You have withdrawn " + cash + " dollars! The new balance is: " + balance);
return true;
}
else System.out.println("Sorry, your balance (" + balance + ") is less than what you have requested (" + cash + ")!");
return false;
}
}
import java.lang.reflect.Field;
public class Test
{
public static void main(String[] args) throws Exception
{
BankAccount myAccount = new BankAccount();
myAccount.withdrawCash(150);
Field f = BankAccount.class.getDeclaredFields()[0];
f.setAccessible(true);
f.set(myAccount, 1000000); // I am a millionaire now ;)
myAccount.withdrawCash(500000);
}
}
OUTPUT:
Sorry, your balance (100.0) is less than what you have requested
(150.0)! You have withdrawn 500000.0 dollars! The new balance is: 500000.0

Because some code is trusted code -- i.e., if a local application wants to do this, maybe it's not a big deal. For untrusted code, though -- i.e., an applet, or a web start application, or RMI stubs, or any other downloaded code -- there's a SecurityManager in place, which (generally based on a policy file) has the opportunity to say "Sorry, Charlie" and deny the setAccessible() request.

Well, once you have released a Java program, anyone is free to reverse engineer, or de-compile, it anyways, so if someone wanted it badly enough, they would probably be able to access your your "privates" anyway.
What you can do however, is to forbid any foreign code to access your stuff in your runtime. That is, if you're for instance using someone else's code you could disable reflections, access to files etc before those libraries are used.
Search for ClassLoader and Security Manager to find out more. Here's something that looks relevant.

Related

Try-Catch statement Java

public void payForMeal(double amount) throws Exception {
if (balance - amount < 0 && amount - balance <= creditLimit) {
this.strStatus = "Using Credit";
double newBalance = balance - amount;
balance = newBalance;
throw new ArithmeticException("\n\n-----------------------------\n" + "You must top-up your balance\n" + "Your new balance is: " + balance + "\n" + "You are: " + strStatus + "\n" + "-----------------------------\n");
}//if
else if (amount > creditLimit && balance < amount) {
throw new ArithmeticException("\n\n----------------------\n" + "Cost of meal exceeds the credit limit." + "\n----------------------\n");
}//elseif
else {
double newBalance = balance - amount;
balance = newBalance;
transCount++;
}//else
}//payForMeal
when balance is 2 and payForMeal is set to 8 the following prints before the program crashes:
Displaying Account Details:
Cost of meal exceeds the credit limit.
Customer ID: 200
Name: Joe
Balance: 2.0
Minimum TopUp: 2.0
Account Status: Valid
Credit Limit: 5.0
Transaction Count: 0
How can I add a try-catch to stop the programming from crashing but still print out the errors, thanks
You should wrap the method which throws the error with the try catch, like so
// ... some code
try {
payForMeal(amount);
} catch (ArithmeticException e) {
System.out.log("An error occurred trying to pay for the meal: " + e.getMessage());
}
// ... more code
How you handle the error is for you to decide.
Try to do less in your methods. Programming is about problem decomposition and design.
Have a checkBalanceSufficient method that returns a result rather than doing this within your code. Check what kind of data it needs to return. Don't put in any print statements, that's for your main method or UI related classes & methods.
Don't reuse ArithmeticException. The calculations are fine, it is the result that you are not happy with. So you need to define your own higher level exception instead (programming an exception is really easy, just extend Exception). Preferably your code will never throw an exception due to problems with the input though; you can handle bad input within separate methods early in your code.
If there is any higher level code (i.e. code that implements a use case) within a catch clause then you are already doing things wrong.

How do I give my simple java program memory?

I am new to programming and I have a simple program I am working on for fun that keeps track of my money. For instance, I want it to record how much money is in my wallet. So I will give it some data, and it complies. However, when I rerun the program at a different time to add or subtract money from my wallet for example, it will revert back to 0 instead of saving the changes I made before.
I assume I have to make a txt file for this data to save to, and then have it read it every time I run the program?
//here is my wallet class
public class Wallet extends UserInterface{
public String WalletName;
public double WalletCash;
public Wallet(String name) {
this.WalletName = name;
}
public String addCashtoWallet(double income) {
WalletCash += income;
return "Added $" + income + "to " + this.WalletName;
}
public String removeCashfromWallet(double cost) {
WalletCash -= cost;
return "Removed $" + cost + "from " + this.WalletName;
}
}
The output when I add money to the wallet for example, will be
"Your wallet now has $64.0 would you like to do anything else"
However, when I run the program again, it will say 0, but I want it to display the 64 dollars I added before. How do I get it to save this data?
You could use a file to keep your information and load the information at the startup.
https://stackabuse.com/reading-and-writing-files-in-java/
Or you can use a database to keep that information.
https://www.tutorialspoint.com/jdbc/jdbc-sample-code.htm
I advice you first to try to use a file, after that you could try using a database (e.g. MySQL, MariaDB, PostgreSQL)
It's not 'memory', it's called 'persistent storage'.
And simple TXT file is a worst solution, like for me. I suggest you to use at least structured file like JSON, but better - an embedded database like HSQLDB.

JUnit testing for a method when else statement outputs error message as String [duplicate]

This question already has answers here:
JUnit test for System.out.println()
(14 answers)
Closed 4 years ago.
I'm working on a program that processes bank transactions. My withdraw method subtracts the amount from the balance and if there aren't enough funds for the withdrawal, an error message is outputted to the screen. The error message is the case I am having trouble testing.
public void withdraw(double amt) {
double bal = getBalance();
if(bal >= amt) {
super.setBalance(bal - amt);
if(bal < minBalance) {
super.setBalance(bal - amt - maintFee);
}
} else {
System.out.println("Error: Not enough funds for withdraw");
}
}
These are my JUnit tests for this method currently. I just need help on testWithdrawThree(). Thank you!
#Test
void testWithdrawOne() {
Savings s = new Savings(500.00, 30.00, "111", "Andrew Green", 1000.00);
s.withdraw(200);
assertEquals(800.00, s.getBalance());
}
#Test
void testWithdrawTwo() {
Savings s = new Savings(500.00, 30.00, "111", "Andrew Green", 400.00);
s.withdraw(200.00);
assertEquals(170.00, s.getBalance());
}
#Test
void testWithdrawThree() {
Savings s = new Savings(500.00, 30.00, "111", "Andrew Green", 400.00);
s.withdraw(600.00);
//Need to check that program will output "Error: Not enough funds for withdrawal"
}
Best approach in my eyes is doing a refactoring as suggested by Yoni already. Alternatively to changing the signature of the method (maybe it's not possible because it's defined in an interface), your original method can call another method that you pass the PrintStream to be used:
public void withdraw(double amt) {
performWithdraw(amt, System.out);
}
void performWithdraw(double amt, PrintStream errorStream) {
double bal = getBalance();
if(bal >= amt) {
super.setBalance(bal - amt);
if(bal < minBalance) {
super.setBalance(bal - amt - maintFee);
}
} else {
errorStream.println("Error: Not enough funds for withdraw");
}
}
Your test class (residing in the same package and therfor able to access performWithdraw) would look something like this:
#Test
void testInvalidWithdraw() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(baos, true, "utf8");
Savings s = new Savings(500.00, 30.00, "111", "Andrew Green", 400.00);
s.performWithdraw(600.00, ps);
assertEquals(400d, s.getBalance());
assertEquals("check error message", "Error: Not enough funds for withdraw", baos.toString("utf8"));
}
BTW: You should test that the balance is unchanged (I added a corresponding assertEquals in my example) and you should check edge cases as well, i.e. check that you get the error message when withdrawing 400.01. Edge cases should also be checked for the cases where mainenance fees are charged or aren't.
BTW2: Using double for monetary amounts is a Bad Thing[TM]. For learning JUnit it's OK but for Real Applications[TM] you should e.g. use BigDecimal instead.
There are a few ways that you can go about this:
You can take ownership of the System.out stream, as explained in this answer and Andrea mentioned in the comment. I don't think this is a very good route to go because it means that you won't be able to run your tests in parallel since System.out is a shared resource across the JVM.
You can refactor your code - maybe your method should return an error if the withdrawal is not successful? You are basically swallowing the error rather than reporting it.
You can test that the balance did not change after the invocation of the method without sufficient funds. I think this is actually the interesting behavior of the system that you want to test, isn't it? Testing the error message that's printed seems superficial. Maybe it will give you coverage for that line of code but is it really the meaning that you want to capture in your test? Is anyone really going to look at the output stream in production and look for this message? This is again another argument to refactor your code ...
Also, a side note: it would go a long way to name your test methods with meaningful names, e.g. testWithdrawWithoutFunds, instead of the generic names testOne, testTwo, etc.

I have this simple stock transaction program to compute gains or losses and nothing is being displayed when I run the program

The purpose of the program is to compute the gains and or losses in a simple stock market transaction and by the end the following information is needed to be displayed; number of shares, amount of purchase, amount of sell, transaction fee paid, and net profit. Here is the code that I have written thus far:
public class StockTransaction {
public static void main(String[]args) {
String name;
int numberShares;
double buyPrice,sellPrice;
Scanner input = new Scanner(System.in);
System.out.print("What's your name?");
name=input.nextLine();
System.out.print("How many shares bought?");
numberShares=input.nextInt();
System.out.print("Buy price?");
buyPrice=input.nextDouble();
System.out.print("Sale price?");
sellPrice=input.nextDouble();
input.close();
System.out.println(name + "here is the information of your stock transactions:");
System.out.println("Number of shares:" + numberShares);
System.out.println("Amount of purchase:" + buyPrice*numberShares);
System.out.println("Amount of sell:" + sellPrice*numberShares);
System.out.println("Transaction fee paid:" + 15 + 15);
System.out.println("Net profit:" + (sellPrice*numberShares-buyPrice));
}
}
In your class, you are seeing a side effect of having too many curly braces. To simplify, your code looks like this:
class StockTransaction {
public static main() {
// this is the content of the main() function
}
{
// this is where your code is.
}
}
In Java, a block of curly-braced code outside of any method acts as an instance initializer. What this means is that when you explicitly create an object, for example with this code:
new StockTransaction();
the code inside the instance initializer will be run in addition to any constructor. This is a convenient way to have some initialization code run no matter what constructor the user chooses to create the object with.
You will notice however that before the main() function is the keyword static. static tells the compiler that the method can be called without an instance of the object. It belongs to the StockTransaction class rather than to a particular instance of the class.
When your program starts, main() is called without an instance of your StockTransaction class. Because there is no instance to initialize, there is no reason for your code to be called.
All of this unfortunately is what I would consider more advanced Java usage, so if it doesn't make a lot of sense now don't worry... it will later as you gain more experience with the language.
In the meantime, all you need to do to get your program to run is to move your code into the main() function and get rid of those extraneous curly braces. It should look like this:
import java.util.Scanner;
public class StockTransaction
{
public static void main(String[]args) {
String name;
int numberShares;
double buyPrice,sellPrice;
Scanner input = new Scanner(System.in);
System.out.print("What's your name?");
name=input.nextLine();
System.out.print("How many shares bought?");
numberShares=input.nextInt();
System.out.print("Buy price?");
buyPrice=input.nextDouble();
System.out.print("Sale price?");
sellPrice=input.nextDouble();
input.close();
System.out.println(name + "here is the information of your stock transactions:");
System.out.println("Number of shares:" + numberShares);
System.out.println("Amount of purchase:" + buyPrice*numberShares);
System.out.println("Amount of sell:" + sellPrice*numberShares);
System.out.println("Transaction fee paid:" + 15 + 15);
System.out.println("Net profit:" + (sellPrice*numberShares-buyPrice));
}
}
looks fine to me ( couple minor output issues )
What's your name?Dave
How many shares bought?1000
Buy price?10
Sale price?5
Davehere is the information of your stock transactions:
Number of shares:1000
Amount of purchase:10000.0
Amount of sell:5000.0
Transaction fee paid:1515
Net profit:4990.0
insert space after users name
when adding numbers together and concatenating with strings, you need parentheses around the numbers.
change this:
System.out.println("Transaction fee paid:" + 15 + 15);
to:
System.out.println("Transaction fee paid:" + (15 + 15));
also look into the line about "Net profit", it has a bug too

Question safe withdraw/deposit using AspectJ

I have question regarding making a bankAccount class implement safe withdraw/deposit function. So far it will print log when you make a withdraw or deposit to the bankAccount class. Anyway my question is how to implement the safety e.g. you cannot withdraw more money than what you have currently in your bankAccount. If I'm not allowed to implement that safety in the bankAccount class, and want to implement it to an AspectJ.
I have the following now. As can be seen the withdraw is done regardless if the if-statement is true or false. Therefore I had to in the else statement deposit back the amount of money, so it would not turn negative. Can this be done in some nicer way possibly?
pointcut checking(BankAccount ba, float x):
call(* BankAccount.withdraw(..)) && target(ba) && args(x);
before(BankAccount b, float x) : checking(b, x) {
if(b.getBalance() >= x) {
System.out.println("Account changing. $" + x + " withdrawn...");
} else {
System.out.println("Account does not have. $" + x + " to withdrawn...");
b.deposit(x);
}
}
I'd say this would be better handled by an around advice, which can prevent proceeding to the normal invocation and substitute some other action instead if the transaction shouldn't be allowed.
The code for the around advice should be basically similar to what you wrote for before, except in the if block you'd have to call proceed to continue into the normal execution, and in the else block you'd no longer need the call to deposit.

Categories

Resources