LocalDateTime format after form Submit - spring

I use the following jQuery function to format my datepicker
$(".datepicker").datepicker({
dateFormat : "MM yy"
}).attr('readonly', true);
Upon selection I can see the text field is set correctly to November 2013. Before form is submitted I am using Spring validation to validate the date with
public class LocalMonthEditor extends PropertyEditorSupport {
#Override
public void setAsText(final String text) throws IllegalArgumentException {
if (!StringUtils.hasText(text)) {
// Treat empty String as null value.
setValue(null);
} else {
LocalDateTime localDateTime = LocalDateTime.parse(text,
DateTimeFormat.forPattern("MMMM yyyy"));
setValue(localDateTime);
}
}
#Override
public void setValue(final Object value) {
super.setValue(value == null || value instanceof LocalDateTime ? value
: new LocalDateTime(value));
}
#Override
public LocalDateTime getValue() {
return (LocalDateTime) super.getValue();
}
#Override
public String getAsText() {
return getValue() != null ? getValue().toString() : "";
}
}
However after form being submitted the text field is changed to 2013-11-01T00:00:00.000. How can I maintain the field to November 2013 ?

First of all, if the data you need is simply a month and a year, why are you using Joda-Time at all? That's like getting in your car to drive to your mailbox at the end of the driveway: extra effort and complexity for no benefit.
Instead, I suggest you choose between:
Track a pair of variables (month, year)
Define your own class with a pair of members (month, year), and track an instance.
Use a String as seems to be your intention: "November 2013" as you seem to be thinking, or a simpler schemes such as "2013-11".
Secondly, because you created an instance of LocalDatetime, at some point toString seems to be called. The default output of toString on a LocalDateTime is output in the standard ISO 8601 format you saw: 2013-11-01T00:00:00.000. A LocalDateTime has a date value and a time value (hence the name), even if the time value may be set to zeros (meaning start of day). So this is a feature, not a bug.
I don't know Spring Validatation nor the rest of your class structure. I'm guessing you are storing a LocalDateTime instance where instead you meant to be (or should be) storing a String instance. You may need to read up on the subject of "model" versus "view". Often we track data behind the scenes differently than we present data to the user. In this case, you probably should be holding a pair of ints or Integers (one for month, one for year) in your model with a String in your view ("November 2013").

You are setting your local time object directly to text field, thats why your getting full date string.convert your date object by using parse() method and set it. Do not create new object for date set your value directly.

Related

How to retrieve data by property in Couchbase Lite?

My documents have the property docType that separated them based on the purpose of each type, in the specific case template or audit. However, when I do the following:
document.getProperty("docType").equals("template");
document.getProperty("docType").equals("audit");
The results of them are always the same, it returns every time all documents stored without filtering them by the docType.
Below, you can check the query function.
public static Query getData(Database database, final String type) {
View view = database.getView("data");
if (view.getMap() == null) {
view.setMap(new Mapper() {
#Override
public void map(Map<String, Object> document, Emitter emitter) {
if(String.valueOf(document.get("docType")).equals(type)){
emitter.emit(document.get("_id"), null);
}
}
}, "4");
}
return view.createQuery();
}
Any hint?
This is not a valid way to do it. Your view function must be pure (it cannot reference external state such as "type"). Once that is created you can then query it for what you want by setting start and end keys, or just a set of keys in general to filter on.

JPA/Hibernate generating wrong SQL in Spring Roo finder method

I'm developing a Spring web application whose persistence layer consists in Spring Roo generated JPA entities, with Hibernate as persistence provider and MySql as underlying DB.
Among my entities I have a class Detection with a tstamp java.util.Date field generated in Roo as follows:
entity jpa --class ~.data.Detection
...
field date --fieldName tstamp --type java.util.Date
...
finder add findDetectionsByTstampBetween
(the finder method was of course chosen after executing finder list)
In my controller code, at a point I invoke:
List<Detection> detections = Detection.findDetectionsByTstampBetween(from, to).getResultList();
Where from and to are two valid java.util.Date(s). When testing sample data though (after ensuring that for a given choice of from, to the returned list shouldn't be empty), I got an empty list and investigated the reasons.
I found in tomcat logs that Hibernate was generating the following SQL:
Hibernate: select detection0_.id as id1_3_, ...etc..., detection0_.tstamp as tstamp4_3_ from detection detection0_ where detection0_.tstamp>=?
I would expect the where clause should contain a trailing "AND detection0_.tstamp<=?", checking the other date range limit. I took a look at the generated Detection.findDetectionsByTstampBetween(Date minTstamp, Date maxTstamp) method in Detection_Roo_Finder.aj and actually the "AND" is present in the invocation to createQuery.
public static TypedQuery<Detection> Detection.findDetectionsByTstampBetween(Date minTstamp, Date maxTstamp) {
if (minTstamp == null) throw new IllegalArgumentException("The minTstamp argument is required");
if (maxTstamp == null) throw new IllegalArgumentException("The maxTstamp argument is required");
EntityManager em = Detection.entityManager();
TypedQuery<Detection> q = em.createQuery("SELECT o FROM Detection AS o WHERE o.tstamp BETWEEN :minTstamp AND :maxTstamp", Detection.class);
q.setParameter("minTstamp", minTstamp);
q.setParameter("maxTstamp", maxTstamp);
return q;
}
Any idea what could cause the problem?
I've finally found the solution to the riddle and, as it turned out, the issue had nothing to do with JPA.
The problem was that the call to the persistence layer was inserted inside a Rest service controller with the following mapping:
#ResponseBody
#RequestMapping(value="/detections", method=RequestMethod.GET, params="from, to" )
public Object getDetectionsInRange(
#RequestParam(required=true) #DateTimeFormat(pattern="yyyy-MM-dd HH:mm") final Date from,
#RequestParam(required=true) #DateTimeFormat(pattern="yyyy-MM-dd HH:mm") final Date to
)
{
...
List<Detection> detections = Detection.findDetectionsByTstampBetween(from, to).getResultList();
...
}
The error was in the definition of the params= argument in #RequestMapping, the correct format being as follows:
#RequestMapping(value="/detections", method=RequestMethod.GET, params={"from", "to"} )
This error caused another version of the controller method for /detections. In this second version I called a different finder method, which appeared to generate the wrong SQL in Hibernate.
#ResponseBody
#RequestMapping(value="/detections", method=RequestMethod.GET )
public Object getDetections(
#RequestParam(required=false, defaultValue="0") int days,
#RequestParam(required=false, defaultValue="0") int hours,
#RequestParam(required=false, defaultValue="0") int minutes
)
{
...
List<Detection> detections = Detection.findDetectionsByTstampGreaterThanEquals( ... ).getResultList();
...
}

Creating a route that can accept a DateTime in the URI with asp.net web api 2 attribute routing

I'm trying to see if I need to write a custom IHttpRouteConstraint or if I can wrestle with the built-in ones to get what I want. I can't see to find any good documentation on this anywhere.
Basically, here's my action:
[Route("var/{varId:int:min(1)}/slot/{*slot:datetime}")]
public async Task<HttpResponseMessage> Put(int varId, DateTime slot)
{
...
}
What I want is to be able to call it like this:
PUT /api/data/var/1/slot/2012/01/01/131516 and have the framework bind 19 to var id and a DateTime with a value of "Jan 1st, 2012, 1:15:16pm" as the "slot" value.
Following the guide from here: http://www.asp.net/web-api/overview/web-api-routing-and-actions/create-a-rest-api-with-attribute-routing I am able to get it to work by passing in just the date segments, i.e. PUT /api/data/var/1/slot/2012/01/01 or PUT /api/data/var/1/slot/2012-01-01, but that only gives me a data value, no time components.
Something tells me that trying to pass in time in any sane way through URI segments is a bad idea, but I'm not sure why it'd be a bad idea, besides the ambiguity regarding local vs UTC times.
I've also tried constraining the datetime constraint with a regex, e.g. {slot:datetime:regex(\\d{4}/\\d{2}/\\d{2})/\\d{4})} to try to get it to parse something like 2013/01/01/151617 as a DateTime, but to no avail.
I'm pretty sure I can get this to work with a custom IHttpRouteConstraint, I just don't want to do something that might be built in.
Thanks!
an option is to pass the DateTime as query string parameters (see [FromUri]
e.g.
[Route("api/Customer/{customerId}/Calls/")]
public List<CallDto> GetCalls(int customerId, [FromUri]DateTime start, [FromUri]DateTime end)
this will have a signature of
GET api/Customer/{customerId}/Calls?start={start}&end={end}
Create the query string dates with
startDate.ToString("s", CultureInfo.InvariantCulture);
query string will look like
api/Customer/81/Calls?start=2014-07-25T00:00:00&end=2014-07-26T00:00:00
Web API datetime constraint doesn't do anything special regarding parsing datetime as you can notice below(source code here).
If your request url is like var/1/slot/2012-01-01 1:45:30 PM or var/1/slot/2012/01/01 1:45:30 PM, it seems to work fine...but I guess if you need full flexibility then creating a custom constraint is the best option...
public bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName, IDictionary<string, object> values, HttpRouteDirection routeDirection)
{
if (parameterName == null)
{
throw Error.ArgumentNull("parameterName");
}
if (values == null)
{
throw Error.ArgumentNull("values");
}
object value;
if (values.TryGetValue(parameterName, out value) && value != null)
{
if (value is DateTime)
{
return true;
}
DateTime result;
string valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
return DateTime.TryParse(valueString, CultureInfo.InvariantCulture, DateTimeStyles.None, out result);
}
return false;
}

Adding the localized Display Name to the constraint violation message?

We are using the new GWT validation library in 2.5.
We are adding an aggregated list of violations to our screen. This list must display the localized field name.
#MyNotNull(foo= "Stage")
public String getStage();
Localized message needs to display
"Stage is a required field"
The message in MyValidationMessages.properties reads
{foo} is a required field
Note that annotations do not allow non-constant values to be assigned to attributes. So we have to get the locale value somehow at design time :/
This will not work
#MyNotNull(foo = injector.getLocale().errorMessage())
public String errorMessage()
How do I use localeKey to look up the locale in the locale files since the property requires a constant?
The solution is to
add something like FieldLocale.properties this is a constants lookup
Add an attribute to your annotation like localeKey
Iterate your ConstraintViolation collection
Use something like the below to get the attribute value
Look up the localized value in your FieldLocale.properties file
Copy the violation and change the message to the localized version
protected String getAttributeValue(ConstraintViolation violation, String key) {
ConstraintDescriptor descriptor = violation.getConstraintDescriptor();
if (descriptor.getAttributes().containsKey(key))
return (String) descriptor.getAttributes().get(key);
return null;
}
protected ConstraintViolation<T> copyMessage(ConstraintViolation<T> violation, String message) {
return ConstraintViolationImpl.<T> builder() //
.setConstraintDescriptor(violation.getConstraintDescriptor()) //
.setInvalidValue(violation.getInvalidValue()) //
.setLeafBean(violation.getLeafBean()) //
.setMessage(message) //
.setMessageTemplate(violation.getMessageTemplate()) //
.setPropertyPath(violation.getPropertyPath()) //
.setRootBean(violation.getRootBean()) //
.setRootBeanClass(violation.getRootBeanClass()) //
.build();
}

Validation Error: value is not valid when using a custom converter [duplicate]

This question already has answers here:
Validation Error: Value is not valid
(3 answers)
Closed 6 years ago.
NetBeans 7.1.1 JSF2.1
When using converter="convK" attribute in h:selectManyCheckBox it all works well. But I tried to use #FacesConverter(forClass=className.class) form and it keeps giving me "Validation is not Valid" errors. I've tried changing it to forClass=packageName.className.class but no help.
This is converter:
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
#FacesConverter( "convK")
public class KorisnikConverter implements Converter{
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value==null) return value;
if (value.isEmpty()) return value;
for (int i=0; i<Arhiva.getSviKor().size(); i++) {
if (Arhiva.getSviKor().get(i).getUsername().equals(value)) {
return Arhiva.getSviKor().get(i);
}
}
return value;
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value==null) return "";
if (value instanceof Korisnik) return ((Korisnik)value).getUsername();
return "";
}
}
I have a class called Korisnik which has couple text fields, username is unique one. In my main managing bean I have couple arrayList of those objects. Goal is to use selectManyCheckBox to chose just some of users and put them in a separate arraylist for some other uses. I wanted to push entire objects around (I can always easily work with strings and have object creation and management in my controler beans but wanted to try custom converters to get selectItems to work with objects)
In my class I've overridden equals and hashCode (as there is a lot of talk about custom converters giving blah blah Validation is not valid errors).
#Override
public boolean equals (Object obj) {
if (obj==null) return false;
if (!(obj instanceof Korisnik)) return false;
Korisnik k = (Korisnik)obj;
return (this.username==k.username);
}
#Override
public int hashCode() {
return this.username.hashCode();
}
Edit. When I'm using it as named converter and using said converter only in that one instance with selectManyCheckbox it works fine even without overriding equals and hashCode.
This is checkbox code
<h:selectManyCheckbox value="#{kontrolg.izabrAut}" layout="pageDirection" converter="convK" >
<f:selectItems value="#{kontrolg.moguciAut}" var="it" itemLabel="# {it.ime} #{it.prezime}" itemValue="#{it}"/>
</h:selectManyCheckbox>
What I don't know is whether I'm failing to properly use forClass="whatever" in converter annotation or my converter actually works ok with that one selectManyCheckbox, but when I specify it in forClass form it gets used for all instances of that object and causes some other code that worked nice before adding custom converters to now give "validation is not valid" error?
The value is not valid validation error will be thrown when the equals() method on the selected item has not returned true for any of the available items.
And indeed, your equals() method is broken. The following line is wrong:
return (this.username==k.username);
I'll assume that username is a String, which is an Object. The == compares Objects by reference, not by their value. In other words, when performing == on two Objects, you're basically testing if they point to exactly the same instance. You're not checking if they represent the same value (say, the Object instance's internal representation). You should be using the Object's equals() method instead, the String#equals() method, here's an extract of relevance from its javadoc:
equals
public boolean equals(Object anObject)
Compares this string to the specified object. The result is true if and only if the argument is not null and is a String object that represents the same sequence of characters as this object.
The == is only applicable when comparing primitives like boolean, int, long, etc or when testing for null.
So, to fix your problem, replace the wrong line by the following line:
return username.equals(k.username);
Or, when they can possibly be null:
return (username == null) ? (k.username == null) : username.equals(k.username);
See also:
Right way to implement equals contract

Resources