Spring boot and BigDecimal or Double serialization problem - spring-boot

İ can not handle BigDecimal initialization properly , i have an entity which has a BigDecimal field like this:
#Entity
public class Menu{
...
#Digits(integer=6, fraction=2)
private BigDecimal price;
...
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
...
other generated getters and setters toString etc.
...
}
And in frontend i use thymeleaf, in html form (which adds and updates new menu item) i have this input for Big Decimal value:
<div class="form-group">
<label for="price">Enter Price</label>
<input type="number" class="form-control" step="0.01" id="price" name="price" th:field="*{price}" placeholder="enter Price" value=" ">
</div>
And for restrict the user to enter more than 2 digit precision on price value, i have a js code like this:
$('#price').keypress(function (e) {
var character = String.fromCharCode(e.keyCode)
var newValue = this.value + character;
if (isNaN(newValue) || parseFloat(newValue) * 100 % 1 > 0) {
e.preventDefault();
return false;
}
});
The question is : when user enters 10.25 value in the form , thymeleaf renders it like 10.2499998.. . Even other rest endpoints returns this entity with value in json like 10.249999. But when i looked at my database (postgresql and offcourse i use jpa) this value seems just fine which is 10.25.
So i know when initializing new BigDecimal value the constructor must be like new BigDecimal("10.25") with string in parameter.But all i have is the default getters and setters and my controller is simple post controller for entity saving like this:
#PostMapping("/additem")
public String addItemPost(#ModelAttribute(value="menu") #Valid Menu menu,Model model,BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return "addmenuitem";
}
this.menuService.saveMenuItem(menu);
return "redirect:/restaurant/menu";
}
The problem 2 is : I tried to change BigDecimal with Double value and after that, the input form takes value as we suggest and i see that value everywhere correctly.But if i write more digit after comma , the js function blocks me to write more than 2 digit but real value again becomes 10.2499999.. .
It must be something with spring's strategy of taking values from thymeleaf form, and than initialize those values into entity , but i never do that manually neighter couldn't debug it.
So ı don't know the problem is if my javascript function or my input form or the variable type.Please help.
Any help will be appreciated.

I found the problem and writing here if anyone encounter a problem like this.
My Problem was not in localhost , but occured on heroku.So i realized that in heroku postgresql db my BigDecimal columns did not updated and in localhost they were changing whenever i re-run because of jdbc table creation strategy choice.
I made the entity attribute Double and changed remote db columns to double precision than problem solved.

Related

MudDatePicker DefaultValue plus DateChange

I want to use MudDatePicker element in a way where I need to be able to set a default value on load but at the same time define a onChange event for it. I am trying to do this but error says "The component parameter is used two or more times for this component". Is there a way I can do this?
<MudDatePicker #bind-Date="#DefaultValue.Value" Label="Date" DateChanged="OnDateChange"
Required="true" Class="mb-3" />
If you have a two-way binding in Blazor i.e. #bind-Date="date", you can convert it to a one-way binding with a change event which must set the value. The two-way binding is just syntax sugar and will do the same behind the scene.
<MudDatePicker Date="#_date" Label="Date" DateChanged="OnDateChange"
Required="true" Class="mb-3" />
#inject ISnackbar Snackbar
#code {
DateTime? _date = new DateTime(2021, 12, 24);
void OnDateChange(DateTime? newDate)
{
_date=newDate;
// here you can do something when the date changes.
Snackbar.Add($"Date changed to {_date}");
}
}
Here is a snippet which you can play around with: https://try.mudblazor.com/snippet/mYcPFPvLnlyEHeOF
Remove the DateChanged="OnDateChange" and change #bind-Date="DefaultValue.Value" to #bind-Date="DefaultValue". For the property DefaultValue create a getter and setter. Because you have two way binding using #bind-Date="DefaultValue", the setter part gets called every time the value is changed.
I've added some sample code below:
DateTime? _defaultValue = DateTime.Now;
private DateTime? DefaultValue
{
get => _defaultValue;
set
{
_defaultValue = value;
OnDateChange();
}
}

How to add ajax to dynamically created primefaces input fields

I want to create a page to allow users to update a mysql table. This table can be changed by client admins so I have to read the table schema and create fields on the fly. I got the basic code for doing that from How to create dynamic JSF form fields and the ajax code from How to add ajax validation to programmatically generated primefaces component.
To create a proof of concept page I use the following code (note, I'm using primefaces):
for (int idx = 1; idx < 3; idx++) {
UIInput input = new InputText();
input.setId("text" + idx);
ValueExpression targetExpression = facesContext.getApplication().getExpressionFactory().createValueExpression(facesContext.getELContext(), "#{viewMakeFields.value}", String.class);
input.setValueExpression("value", targetExpression);
AjaxBehavior ab = new AjaxBehavior();
ab.setAsync(true);
ab.setProcess("text"+idx);
input.addClientBehavior("blur", ab); // "change" doesn't work either
form.getChildren().add(input);
}
Then, in the getter and setter, I'm getting the component ID to identify which field is changed:
public static String getCallingComponentID() {
UIComponent component = UIComponent.getCurrentComponent(FacesContext.getCurrentInstance());
return component.getId();
}
public String getValue() {
String id = getCallingComponentID();
System.out.println("getValue " + id);
return text1;
}
public void setValue(String text1) {
String id = getCallingComponentID();
System.out.println("setValue " + id);
this.text1 = text1;
}
The ajax isn't firing and when I click the submit button I get (and I know mixing partial and full submits isn't good):
INFO: getValue text1
INFO: getValue text2
INFO: getValue text1
INFO: getValue text2
INFO: setValue j_id1
INFO: setValue j_id1
INFO: getValue text1
INFO: getValue text2
I see two possible solutions: get ajax working so that the component calling the setter has the correct id or get the form submit to identify which child is calling the setter. The former is preferable since I want to disable the save button until something has changed but I'm willing to accept the latter at this point. Any help would be much appreciated.
Turns out this code does work. Somewhere in my meandering the error changed and I didn't understand the significance of that. Replacing head with h:head in the xhtml file that I was adding the fields to makes ajax work.

Using Cache in Play Framework

I'm trying to implement a quiz application. The application loads the questions with ajax one by one. When a user clicks the 'to next question' button his/her answer is saved in cache. But when I debug, cache list is always null...
This code creates the first cache array:
public static void viewQuiz(#Required String user, #Required String test) {
if(validation.hasErrors()) {
flash.error("Hoop kullanıcı lazım…");
index();
} else{
TestClass selectedTest = TestClass.find("title", test).first();
List<String> choiceList = new ArrayList<String>();
session.put("testID", selectedTest.id);
Cache.set("choices", choiceList, "30mn");
render();
}
}
And this code is trying to save the answers one by one:
public static void question(#Required Long id, String answer){
Long testId = Long.parseLong(session.get("testID"));
TestClass test = TestClass.findById(testId);
List<Question> questList = Question.find("test_id", test.id.intValue()).fetch();
Question quest = questList.get(id.intValue());
if(answer != null){
List<String> choiceList= Cache.get("choices",List.class);
choiceList.add(id.intValue(), answer);
Cache.set("choices", choiceList, "30mn");
}
int count = questList.size()-1;
render(quest, count, id);
}
And this code is the html view of the second:
#{extends 'main.html' /}
#{set title:'question.html' /}
<script type="text/javascript">
var questionId = ${id};
$('#nextButton').click(function(){
$('#questionDiv').html('<p><img id = "loaderGif" src="public/images/loading.gif"/></p>');
$('#questionDiv').load("/test/" + ++questionId);
});
$('#endButton').click(function(){
$('#questionDiv').html('<p><img id = "loaderGif" src="public/images/loading.gif"/></p>');
$('#questionDiv').load("/result");
});
</script>
<legend>Soru ${id+1}</legend>
<p>&{quest.question}</p>
#{list items:quest.choices, as:'choice'}
<p><input type="radio" name = "answer" id = "answer" size="30" value="${choice}"/>&{choice}</p>
#{/list}
#{if id < count}
<input id = "nextButton" name="nextButton" type="button" value="İleri"/>
#{/if}
#{else}
<input id = "endButton" name="endButton" type="button" value="Bitti"/>
#{/else}
Don't use the cache to 'store' objects. Either store it in the session or create a new model to store the answers. Generally, you cannot expect the cache to retain the objects you put into; it's a cache, not a store.
To quote from the Play! website: http://www.playframework.org/documentation/1.2.2/cache
It is important to understand that the cache contract is clear: when
you put data in a cache, you can’t expect that data to remain there
forever. In fact you shouldn’t. A cache is fast, but values expire,
and the cache generally exists only in memory (without persistent
backup).
Cache is not reliable and you may get it as null in dev mode. This is expected and you can try changing it to prod mode and see its behavior.

Linq query is triggered multiple times without any apparent reason

I’m trying to optimize my app, and I notice that one query is triggered multiple times without any apparent reason.
Is a MVC 3 App, razor and I’m using Linq and EF.
I have ViewModel class with a couple of properties.
One of these properties is the model for to view.
This is my controller (I omit all the others properties initialization):
public ActionResult companyDetail(Guid id)
{
companyDetailsViewModel myModel = new companyDetailsViewModel();
myModel.companyDetail = companiesRepository.getCompany(id);
return View(myModel);
}
This is my getCompany method:
public company getCompany(Guid id)
{
return db.companies.Single(c => c.id == id);
}
The view is too long to paste here, but is a simple view.
This is a part for example:
<div id="companyName">
<h2>
#Model.companyDetail.companyName
</h2>
</div>
<div id="companyInfoWapper">
<div class="companyInfo">
<h5>
industry: #Model.companyDetail.industry<br />
revenue: #String.Format("{0:C}", Model.companyDetail.revenue)
</h5>
</div>
</div>
I’m using AnjLab SQL Profiler to view the transactions..
When I call the view, the query it’s
called 3 times.
The Generated SQL is
the exact same on all 3.
The transaction ID is different, and also
the duration varies a little bit.
The rest are pretty much the same.
Any Idea what can be making this query to run multiple times?
Another Question!
Anyone know why db.companies.Single(c => c.id == id) ask for top 2? Like this:
SELECT TOP (2)
[Extent1].[id] AS [id], ….
Thanks in Advance!
Edgar.
Update!
The third call was my fault, and I fix it. However, I find this:
The application is Multi-language, so I write a class that implements Controller.
I trace the problem to this class. The query is triggered the second time at the end of the class when I call the Base:
base.Execute(requestContext);
and of course, the action is called again.
Any Idea how to prevent this?
Another Update!
Linkgoron ask why I call Base.Execute(), the answer is because of the localizedController implementation.
But his question make me think, and there is another part of the code:
public abstract class LocalizedControllerBase : Controller
{
public String LanguageCode { get; private set; }
private String defaultLanguage = "es";
private String supportedLanguages = "en|es|pt";
protected override void Execute(RequestContext requestContext)
{
if (requestContext.RouteData.Values["languageCode"] != null)
{
LanguageCode = requestContext.RouteData.Values["languageCode"].ToString().ToLower();
if (!supportedLanguages.ToLower().Contains(LanguageCode))
{
LanguageCode = defaultLanguage;
}
}
else {
LanguageCode = defaultLanguage;
}
System.Globalization.CultureInfo culture = System.Globalization.CultureInfo.CreateSpecificCulture(LanguageCode);
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
base.Execute(requestContext);
}
}
My controller are defined like this:
public class companiesController : LocalizedControllerBase
I put a break point in “Base.Execute” and another in the “return View(myModel)” in the controller.
When I call the view companyDetail, the first stop is in base.Execute, the second is in return view, but for some reason there is a third stop in Base.Execute and a fourth in Return View, and finally the view is render.
This is making me crazy!
Anyone know why db.companies.Single(c
=> c.id == id) ask for top 2? Like this:
SELECT TOP (2) [Extent1].[id] AS [id],
….
Single() throws an exception if there is not exactly one match - so the Linq to Entities provider translates that as a top 2 query which is enough data to make a decision - throw an exception if the query returns 2 results or none, return the only result otherwise.
This doesn't make sense. If the query is executed multiple times you must call GetCompany method multiple times. Once you call Single the query is executed and Company instance is materialized so using it multiple times in view will not cause new executions. Those another calls must be caused by different part of your code.
Btw. you can avoid them by using Find (in EF 4.1) or GetObjectByKey (in EFv1 and EFv4) instead of Single. Single always executes query in database whereas Find first checks if the entity with the same entity key was already loaded and returns the instance without executing db query:
This is code for DbContext API (EF 4.1):
public company getCompany(Guid id)
{
// Id must be primary key
return db.companies.Find(id);
}
Code for ObjectContext API is little bit complicated because you first have to build EntityKey which requires entity set name. Here I described full example which works with different key types and names.

Validation errors not rendered in the view

I'm having a hard time figuring this validation problem. I have one parent domain class defined as follows:
class Person {
String fullName
List telephones = []
static hasMany = [telephones : Telephone]
static constraints = {
fullName(size:3..50, blank:false, nullable:false)
}
}
Then a sublcass:
class SalesAdvisor extends Person{
Float comission //In percentage
Portfolio customerPortfolio
Inventory inventory
static constraints = {
comission(range:0..100, scale:2, nullable:false)
customerPortfolio(nullable:false)
inventory(nullable:false)
}
}
In the SalesAdvisorController I save SalesAdvisor instances:
def save = {
def portfolio = new Portfolio()
def inventory = new Inventory(name:'${params.fullName}Inventory', description:"${params.fullName}'s Inventory")
params.customerPortfolio = portfolio
params.inventory = inventory
def salesAdvisor = new SalesAdvisor(params)
if(!salesAdvisor.hasErrors() && salesAdvisor.save()){
log.info("New instance of SalesAdvisor saved.")
redirect(action:show, id:salesAdvisor.id)
}else{
log.error("There was an error saving the sales advisor.")
salesAdvisor.errors.allErrors.each{
println it.code
}
render(view:'create', model:[salesAdvisor:SalesAdvisor])
}
}
In order to display any errors, in the 'create' view I have:
<g:hasErrors bean="${salesAdvisor}">
<div class="errors">
<g:renderErrors bean="${salesAdvisor}" as="list" />
</div>
</g:hasErrors>
Validation seems to be working fine. However if I submit a string instead of a float for the comission field, in logs I can see "typeMismatch" but the view renders nothing! The message.properties file has a default entry for typeMismatch. Same thing for the fullName field, in logs I can see "nullable" and "blank" errors, but the view renders nothing.
I'm guessing it's more the view's fault than the controller or the domain, since unit tests behave like they should.
I'd say the problem is a simple typo in your model-passing code:
render(view:'create', model:[salesAdvisor:SalesAdvisor])
(note the uppercase SalesAdvisor value). Try
render(view:'create', model:[salesAdvisor:salesAdvisor])
As a side note, there is a bug in your Inventory constructing code:
name:'${params.fullName}Inventory'
You should use double-quotes here (GString).

Resources