Java Annotations: Changing Data using Anotations - java

Perhaps I am overreaching on the use of JAVA annotations, but can someone explain to me whether what I am trying to achieve is possible. If it is, please point me in the right direction.
I have a simple emum containing currencies that are to be used in my application.
public enum Currency{
EURO, DOLLARS
}
I want to persist an amount BigDecimal together with its associated currency. I want to be able to retrieve both whenever needed. I know I can change the amount to string and concatenate them but isn't there a smarter way to do it, perhaps using annotations?

You could just create an object named Money like so:
public class Money{
private Currency currency;
private BigDecimal amount;
public Money(Currency currency, BigDecimal amount){
this.currency = currency;
this.amount = amount;
}
public Currency getCurrencyType(){
return currency;
}
public BigDecimal getAmount(){
return amount;
}
}
Then to create an object from this class, you would just write something like this:
Money money = new Money(Currency.EURO, new BigDecimal("24322.21"));
And then you can retrieve the values for by calling the get functions:
System.out.println(money.getAmount().toString() + " " + money.getCurrencyType());

Related

Reduce a flux to mono using data from flux

I have this scenario. I have one paginated API which gives me the data for last 12 months. The response of the API is like:
public class PagedTransfersDto {
private List<Transfer> content;
private Page page;
#Getter
public static class Transfer {
private String id;
private Long transferId;
private Long transferRequestId;
private String status;
private BigDecimal accountReceivable;
private BigDecimal accountPayable;
private BigDecimal netReceivable;
private BigDecimal netPayable;
private String currency;
private Long transferDate;
}
#Getter
public static class Page {
private Integer size;
private Integer number;
private Integer totalElements;
private Integer totalPages;
}
}
Now I have to collect all the data and then calculate the sum of all the netReceivable and return as a Mono<CompanyIncome>. This pojo is like
public class CompanyIncome {
private BigDecimal inferredIncome = new BigDecimal(0);
}
To do this I have written something like:
CompanyIncome initialIncome = new CompanyIncome();
return myService.getTransfers(0, 50, fromDate, toDate)
.expand(pagedTransfersDto -> {
if (pagedTransfersDto.getPage().getNumber().equals(pagedTransfersDto.getPage().getTotalPages())) {
return Mono.empty();
}
return myService.getTransfers(pagedTransfersDto.getPage().getNumber() + 1, 50, fromDate, toDate);
})
.flatMap(pagedTransfersDto -> Flux.fromIterable(pagedTransfersDto.getContent()))
.reduce(initialIncome, ((companyIncome, transfer) -> {
companyIncome.setInferredIncome(companyIncome.getInferredIncome().add(transfer.getNetReceivable()));
return companyIncome;
}));
Now the catch is that it is possible that this data is only for 3 months in which case I have to extrapolate this to 12 months by multiplying by 4.
What I am thinking is to get the first item of transfers list and the last one and the see if the data is not for a whole year but cant think of a place where to perform this operation.
Since after reduce the transfers data is gone. Before that I cannot seem to find a way how to get this info and still reduce from transfers flux
I am a little new to reactive way and cant seem to find a way to do this. Any help will be greatly appreciated. Thanks
For that purpose, the best solution is to store the necessary "metadata" in the reduced object. You already have a CompanyIncome object, so maybe that is a good place? Otherwise I'd introduce either a Tuple2 or some intermediate business object (eg. CompanyIncomeAggregator) into which to store both the aggregated income and the information that you need to decide at the end if further processing is necessary.
Then in a map step, you'd read that information, act on it and either return the computed income as is or modified according to your criterion.
Important note: Using variables external to the reactive chain is a code smell, as it introduces leaky shared state: if two subscriptions are made to the same Mono, they'll work on the same CompanyIncome object. You can remediate here by using reduceWith, which takes a Supplier for the initial value: reduceWith(CompanyIncome::new, ...).

How Should I write JUnit test in the following case?

I am new in the Unit Testing.
I have a class Ckeckout which main function is to print the amount to be paid for books. The user types the titles of the books in the command line, and based on some calculations I have to output the final price.
Here is the Book class:
public class Book {
private String title;
private double price;
private int year;
public Book(String title, double price, int year) {
super();
this.title = title;
this.price = price;
this.year = year;
}
}
And here is the Checkout class:
public class Checkout {
private List<Book> books;
public Checkout(List<Book> books) {
super();
this.books = books;
}
//calculate the final price
private double getPrice(){
//return some double
}
}
What I want to test is just getPrice method. However, to do so, do I have to create list of Book objects in my CheckoutTest? Also, I will have to verify the final result with some very long number (like 62.01997301). Isn't it easier, to test the main() method, since in my Unit test, there won't be any need to create the Book objects (I will work only with Strings) and I can verify the output with shorter number (like 62.01)?
However, to do so, do I have to create list of Book objects in my CheckoutTest?:Generally and in any kind - yeah!
Also, I will have to verify the final result with some very long number (like 62.01997301): Naah, this depends on your targeting test/code quality! (for a "price" 2 digits should be sufficient (in any country!?))
Isn't it easier, to test the main() method, since in my Unit test, there won't be any need to create the Book objects (I will work only with Strings) and I can verify the output with shorter number (like 62.01)? Definitely! But with the current setup some (human) would have to check the console for "passing that test", for JUnit(and programmatically testing the value), you should/will need to make "getPrice() more visible" ... or in some way access its value.

About ArrayList in java

I want to add some different types elements into the same index in ArrayList.For example:
List account= new ArrayList();
String name;
int number;
float money;
account.add(0,name);
account.add(1,number);
account.add(2,money);
But now , i want to take String name , int number and float money save into the same index.How to do it ?If Arraylist can't. How can i do act this function?
i want to take String name , int number and float money save into the
same index.How to do it ?
You should create a model class named Account. Than define a list like List<Account>.
class Account{
String name;
int number;
float money;
// Constructor, Getter setter etc.....
}
List<Account> list= new ArrayList<Account>();
list.add(new Account("Name", 123, 50.0));
Than, account information will be at account instance at same index. You can access the Account data using list.get(index) method.
Alexis C. is right (in the question's comments).
You'll have to use a class to represents what is an account.
Then you'll be able to create instances of this class for all accounts.
Example :
class Account {
String name;
int number;
float money;
Account(String name, int number, float money) {
this.name = name;
this.number = number;
this.money = money;
}
}
// And somewhere else you'll want to use that class :
List<Account> accounts = new ArrayList<>();
account.add(new Account("Account1", 1, 1f));
account.add(new Account("Account2", 2, 2f));
account.add(new Account("Account3", 3, 3f));
I suggest you to consider learning basic object oriented programming (ie:Composition, Inheritance, Polymorphism)
Hope this example help.
PS : In a real life application, I would recommend the use of the BigDecimal class to handle money, as float (and double) have precision problems.

Using Realm.io to store money values

I'm starting to play with Realm.io in an Android app that I'm writing. In one of my data objects, I'm required to store a currency value. Previously I had stored the value internally as a BigDecimal value and then converted that too and from a double value when moving in and out of the database.
I have always been told that it is a bad idea to store currency values in a double because of the way that they are handled.
Unfortunately, Realm.io doesn't support the storage and retrieval of BigDecimal objects.
Is the best solution to write my own currency class that extends RealmObject and keeps that as a member variable of by data object?
Emanuele from Realm here.
You are right, using floats or doubles for currency is a bad idea.
We don't support BigDecimal for now, and before we do we will have to see how that plays in relation to all other language bindings since we want realm files to be compatible across all the supported platforms.
Christian's idea is good, but I see the conversion to and from String to be a bit slow. If you don't need the arbitrary precision property of BigDecimal you could use long and multiply/divide by the factor your required precision calls for. This would also save a lot of space in terms of the size of the Realm file since integer values are bit packed.
That could work, but would probably be suboptimal if do calculations on your current BigDecimal objects.
You could also use the #Ignore annotation to provide a wrapper method for your custom objects like this:
public class Money extends RealmObject {
private String dbValue;
#Ignore private BigDecimal value;
public String getDbValue() {
return dbValue;
}
public void setDbValue(String dbValue) {
this.dbValue = dbValue;
}
public BigDecimal getValue() {
return new BigDecimal(getDbValue());
}
public void setValue(BigDecimal value) {
setDbValue(value.toString());
}
}
It is not perfect as you need to expose the *dbValue() methods, but it should work.
I would also suggest going to https://github.com/realm/realm-java/issues and make a feature request for this as BigDecimal is probably one of those java classes used by so many that it could warrant native Realm support, just like Date has.
What I do is store it as long
I have defined in my application a constant like so:
public static final BigDecimal MONEY_PRECISION = new BigDecimal(1000);
and when I need to store a big decimal it goes like this:
public class MoneyClass extends RealmObject {
long _price = 0;
public void set_price(BigDecimal price) {
this._price = price.longValue() * App.MONEY_PRECISION.longValue();
}
public BigDecimal get_price() {
return new BigDecimal(_price).divide(App.MONEY_PRECISION, 0, 0);
}
}
In theory this should be faster than saving it on strings , but I haven't really looked at the realm code much
My solution:
Define Interface:
public interface RealmConvert {
void convertToDB();
void convertToObj();
}
Define Entity:
#Ignore
private BigDecimal balance;
private String balanceStr;
#Override public void convertToDB() {
if (getBalance() != null) {
setBalanceStr(getBalance().toString());
}
}
#Override public void convertToObj() {
if (getBalanceStr() != null) {
setBalance(new BigDecimal(getBalanceStr()));
}
}
Before you copyToRealm:call method convertToDB
When you need to use the entity: call method convert obj
It's not an elegant solution, but it works.
Christian Melchior's answer doesn't work in my app.

How do I map a BigDecimal in Hibernate so I get back the same scale I put in?

In Java, new BigDecimal("1.0") != new BigDecimal("1.00") i.e., scale matters.
This is apparently not true for Hibernate/SQL Server, however. If I set the scale on a BigDecimal to a particular value, save the BigDecimal to the database via Hibernate and then re-inflate my object, I get back a BigDecimal with a different scale.
For instance, a value of 1.00 is coming back as 1.000000, I assume because we're mapping BigDecimals to a column defined as NUMERIC(19,6). I can't just define the column as the required scale as I need to store both Dollar and Yen values (for example) in the same column. We need to represent the BigDecimals as numeric types in the database for the benefit of external reporting tools.
Does there exist a Hibernate UserType which maps BigDecimal "properly", or do I have to write my own?
Just for informational sake, I can tell you that the creation of the BigDecimal coming back from the database is done by the proprietary JDBC driver's implementation of the 'getBigDecimal' method of the database-specific 'ResultSet' sub-class.
I found this out by stepping thru the Hibernate source code with a debugger, while trying to find the answer to my own question.
I think this will work, I didn't test it though.
public class BigDecimalPOJO implements Serializable {
private static final long serialVersionUID = 8172432157992700183L;
private final int SCALE = 20;
private final RoundingMode ROUNDING_MODE = RoundingMode.CEILING;
private BigDecimal number;
public BigDecimalPOJO() {
}
public BigDecimal getNumber() {
return number.setScale(SCALE, ROUNDING_MODE);
}
public void setNumber(BigDecimal number) {
this.number = number.setScale(SCALE, ROUNDING_MODE);
}
}
Not sure, but you can check equality using a.compareTo(b) == 0.

Categories

Resources