So, I have a property SQL.Date in my POJO class. I want to bind it using Binder from Vaadin Component, but always returned like this:
Property type 'java.sql.Date' doesn't match the field type 'java.time.LocalDate'. Binding should be configured manually using converter.
So here's my Getter Setter contained in the POJO class
public Date getDateOfBirth() {
return dateOfBirth;
}
public void setDateOfBirth(Date dateOfBirth) { this.dateOfBirth = dateOfBirth; }
And here's when I use the Binder component:
binder = new Binder<>(Person.class);
binder.bindInstanceFields( this );
FYI, I use Spring Boot JPA for the data. Is there any relation between the error message and usage of Spring Boot?
This
Property type 'java.sql.Date' doesn't match the field type
'java.time.LocalDate'. Binding should be configured manually using
converter.
tells what to do. Without seeing your code I assume you have Vaadin DateField in some Vaadin FormLayout that you are trying to populate with java.sql.Date value (or binder.bindInstanceFields() tries).
Unfortunately DateField seems to accept only LocalDate. Therefore you need to convert the value somehow.
There are lots of different "date" converters in vaadin Converter type hierarchy but this one is missing (or maybe I missed it?) so I created it:
public class SqlDateToLocalDateConverter
implements Converter<LocalDate,java.sql.Date> {
#Override
public Result<java.sql.Date> convertToModel(LocalDate value,
ValueContext context) {
if (value == null) {
return Result.ok(null);
}
return Result.ok( java.sql.Date.valueOf( value) );
}
#Override
public LocalDate convertToPresentation(java.sql.Date value,
ValueContext context) {
return value.toLocalDate();
}
}
It seems that you are using declarative ui? I am no able to tell it now howto port this with that with little effort.
If you were binding fields manually it would go like this:
binder.forField(myForm.getMyDateField())
.withConverter(new SqlDateToLocalDateConverter())
.bind(MyBean::getSqlDate, MyBean::setSqlDate);
So i guess you need to find a way to add this converter to handle assumed DateField. Anyway message suggests that you might not be able to use the easy way binder.bindInstanceFields() but bind fields manually.
You can create a custom date field and use it instead of DateField. Then you don't need to bind it every time just use automated binding
public class CustomDateField extends CustomField<Date> {
DateField dateField;
public CustomDateField(String caption) {
setCaption(caption);
dateField = new DateField();
dateField.setDateFormat("dd/MM/yy");
}
#Override
protected Component initContent() {
return dateField;
}
#Override
protected void doSetValue(Date date) {
dateField.setValue(date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
}
#Override
public Date getValue() {
return dateField.getValue() != null ? Date.from(dateField.getValue().atStartOfDay(ZoneId.systemDefault()).toInstant()) : null;
}
}
Related
Enum
public enum EmployeeStatus {
ACTIVE, IN_ACTIVE
}
In callers scattered all over the application whicg get and set the enum like below. Here are examples
Caller_1
if(employee.getStatus() == EmployeeStatus.STATUS.SUBMITTED) {
}
Caller_2
employee.setStatus(EmployeeStatus.STATUS.SUBMITTED)
Problem
I need to implement the internationalization so that end user sees the employee status as per locale. So when i set the status for french locale
it should set the value from right resource bundel. Is there a way i can achieve this without changing the caller code. Here is the solution
I can think of
My proposed solution :-
public enum EmployeeStatus {
ACTIVE, IN_ACTIVE
public static String toString() {
return I18n.getMessage("label." + this);
}
}
public final class I18n {
private I18n() {
}
private static ResourceBundle bundle;
public static String getMessage(String key) {
if(bundle == null) {
bundle = ResourceBundle.getBundle("path.to.i18n.messages");
}
return bundle.getString(LocaleContextHolder.getLocale());
}
}
With this approach I need to add toString method in every Enum without change in caller ? Is there a better generic approach spring provides ?
I am using spring 4. See if spring can help here .
Introduction
The lead architect went and changed the ENUM definition in a spring boot project.
From:
public enum ProcessState{
C("COMPLETE"), P("PARTIAL");
}
To:
public enum ProcessState{
COMPLETE("COMPLETE"), PARTIAL("PARTIAL");
}
What is the proper way to deal with this? Some other Java Spring Boot applications are now breaking. Would there be a way to tell the jackson deserializer to perform some kind of conversion in these situations?
My Current Work-Around
What I did was to run two update statements on the oracle database:
UPDATE store set PAYLOAD = REPLACE(PAYLOAD, '"processState":"P"','"processState":"PARTIAL"') where PAYLOAD like '%"processState":"P"%';
UPDATE store set PAYLOAD = REPLACE(PAYLOAD, '"processState":"C"','"processState":"COMPLETE"') where PAYLOAD like '%"processState":"C"%';
Question
So are there other ways? Could I do it by adding some deserialization/conversion code somewhere for these specific cases? Is there a more elegant way than running a replace SQL statement?
Could I do some kind of hack on a specific java sub-package, and say "use this enum instead of that enum..." or use one of the two? But without affecting the rest of the code?
The error:
java.lang.IllegalArgumentException: No enum constant
Ideally we store value of emum rather than Enum.
So, you should save ENUM values like COMPLETE,PARTIAL
For JSON serialization and de-serialization, use #JsonValue
#JsonValue
public String toValue() {
return value;
}
One additional solution to the others posted:
#JsonCreator
public static ProcessState factory(String inputValue) {
if(inputValue.length() == 1){
for(ProcessState type : ProcessState.values()){
if(inputValue.equals(type.getValue().substring(0,inputValue.length()))){
return type;
}
}
}
return ProcessState .valueOf(inputValue);
}
Implement a JPA converter like this:
#Converter(autoApply = true)
public class ProcessStateConverter
implements AttributeConverter<ProcessState, String> {
private ImmutableBiMap<ProcessState, String> map = ImmutableBiMap.<ProcessState, String>builder()
.put(COMPLETE, "C")
.put(COMPRESSING, "P")
.build();
#Override
public String convertToDatabaseColumn(ProcessState attribute) {
return Optional.ofNullable(map.get(attribute))
.orElseThrow(() -> new RuntimeException("Unknown ProcessState: " + attribute));
}
#Override
public ProcessState convertToEntityAttribute(String dbData) {
return Optional.ofNullable(map.inverse().get(dbData))
.orElseThrow(() -> new RuntimeException("Unknown String: " + dbData));
}
}
Remember to treat your Enum like a simple column and not #Enumerated i.e.
#Entity
public class MyEntity {
#Column //no #Enumerated
private ProcessState processState;
//...
}
The drawback is that you need to maintain the converter each time something changes. So better create a unit test to check if everything is correctly mapped.
I have lots of beans and all use LocalDate and LocalDateTime. The DateTextField in Wicket and all other widgets (like the DatePicker) only work on java.util.Date. Is there any way to inject a converter into Wicket 7 so that it uses LocalDate or LocalDateTime?
The beans look like this:
public class SomeBean {
Long id = null;
LocalDate since = null;
// plus getters and setters
}
A Wicket form currently uses a CompoundPropertyModel
CompoundPropertyModel<SomeBean> model = new CompundPropertyModel<>( bean );
You can wrap your LocalDate and etc. models in a IModel<java.util.Date>, e.g.
public static class LocalDateModel implements IModel<java.util.Date> {
private IModel<LocalDate> localDateModel;
public LocalDateModel(IModel<LocalDate> localDateModel){
this.localDateModel = localDateModel;
}
#Override
public Date getObject() {
return convertLocalDateToUtilDateSomehow(localDateModel.getObject());
}
#Override
public void setObject(Date object) {
localDateModel.setObject(convertUtilDateToLocalDateSomehow(object));
}
#Override
public void detach() {
localDateModel.detach();
}
}
If you then feed models like this into the form components you want to use it should work just fine.
If you want your CompoundPropertyModel to automatically provide such wrapping models, you need to extend it and override it's CompoundPropertyModel#wrapOnInheritance(Component component) method to infer that a wrapping model is needed. Something like
#Override
public <C> IWrapModel<C> wrapOnInheritance(Component component)
{
IWrapModel<C> actualModel = super.wrapOnInheritance(component);
if (actualModel.getObject() instanceOf LocalDate) {
return new LocalDateModelButAlsoWrapping(actualModel);
} else {
return actualModel;
}
}
Where LocalDateModelButAlsoWrapping is unsurprisingly just an extension of LocalDateModel example above but which also implements IWrapModel<T>.
If you use this extension instead of your regular CompoundPropertyModel it would detect when fields are LocalDate and provide models to components (like your DateTextField) that are wrapped to look like java.util.Date models.
The code snippet I gave you is rather dirty though (you should probably not get the model object to infer its type) as I have only provided it to illustrate the general mechanism, so I suggest you devise your own way to infer the type of object expected (e.g. you can check if the Component argument is a DateTextField), but this is the general direction of the solution that I can imagine.
You can register your own converters:
https://ci.apache.org/projects/wicket/guide/7.x/guide/forms2.html#forms2_3
#Override
protected IConverterLocator newConverterLocator() {
ConverterLocator defaultLocator = new ConverterLocator();
defaultLocator.set(Pattern.class, new RegExpPatternConverter());
return defaultLocator;
}
Related: https://issues.apache.org/jira/browse/WICKET-6200
You can simply backport the converter classes from Wicket 8. You'll find these attached to this commit: https://issues.apache.org/jira/browse/WICKET-6200 (AbstractJavaTimeConverter and whatever subclasses you need for LocalDate, LocalDateTime, LocalTime, etc.)
Of course, that will not help with a DateTextField, because that has the Date type parameter hardcoded. For such, you can either create your own subclasses using the above converters, or use regular Label and TextField, with converters registered globally, as shown below:
#Override
protected IConverterLocator newConverterLocator() {
ConverterLocator converterLocator = new ConverterLocator();
converterLocator.set(LocalDateTime.class, new LocalDateTimeConverter());
converterLocator.set(LocalDate.class, new LocalDateConverter());
converterLocator.set(LocalTime.class, new LocalDateConverter());
return converterLocator;
}
Here's a simple value bean annotated with Spring's new (as of 3.0) convenience #DateTimeFormat annotation (which as I understand replaces the pre-3.0 need for custom PropertyEditors as per this SO question):
import java.time.LocalDate;
import org.springframework.format.annotation.DateTimeFormat;
public class Widget {
private String name;
#DateTimeFormat(pattern = "MM/dd/yyyy")
private LocalDate created;
// getters/setters excluded
}
When biding the values from a form submission to this widget, the date format works flawlessly. That is, only date strings in the MM/dd/yyyy format will convert successfully to actual LocalDate objects. Great, we're halfway there.
However, I would also like to be able to also display the created LocalDate property in a JSP view in the same MM/dd/yyyy format using JSP EL like so (assuming my spring controller added a widget attribute to the model):
${widget.created}
Unfortunately, this will only display the default toString format of LocalDate (in yyyy-MM-dd format). I understand that if I use spring's form tags the date displays as desired:
<form:form commandName="widget">
Widget created: <form:input path="created"/>
</form:form>
But I'd like to simply display the formatted date string without using the spring form tags. Or even JSTL's fmt:formatDate tag.
Coming from Struts2, the HttpServletRequest was wrapped in a StrutsRequestWrapper which enabled EL expressions like this to actually interrogate the OGNL value stack. So I'm wondering if spring provide something similar to this for allowing converters to execute?
EDIT
I also realize that when using spring's eval tag the date will display according the pattern defined in the #DateTimeFormat annotation:
<%# taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<spring:eval expression="widget.created"/>
Interestingly, when using a custom PropertyEditor to format the date, this tag does NOT invoke that PropertyEditor's getAsText method and therefore defaults to the DateFormat.SHORT as described in the docs. In any event, I'd still like to know if there is a way to achieve the date formatting without having to use a tag--only using standard JSP EL.
You may use the tag to provide you these kind of formattings, such as money, data, time, and many others.
You may add on you JSP the reference:
<%# taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
And use the formatting as:
<fmt:formatDate pattern="yyyy-MM-dd" value="${now}" />
Follows below a reference:
http://www.tutorialspoint.com/jsp/jstl_format_formatdate_tag.htm
To precise Eduardo answer:
<%# taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<fmt:formatDate pattern="MM/dd/yyyy" value="${widget.created}" />
I also prefer to not do any formatting via tags. I realise this may not be the solution you are looking for and are looking for a way to do this via spring annotations. Nevertheless, In the past I've used the following work around:
Create a new getter with the following signature:
public String getCreatedDateDisplay
(You can alter the name of the getter if you prefer.)
Within the getter, format the created date attribute as desired using a formatter such as SimpleDateFormat.
Then you can call the following from your JSP
${widget.createDateDisplay}
I was dispirited to learn that spring developers have decided not to integrate Unified EL (the expression language used in JSP 2.1+) with Spring EL stating:
neither JSP nor JSF have a strong position in terms of our development focus anymore.
But taking inspiration from the JIRA ticket cited, I created a custom ELResolver which, if the resolved value is a java.time.LocalDate or java.time.LocalDateTime, will attempt to pull the #DateTimeFormat pattern value in order to format the returned String value.
Here's the ELResolver (along with the ServletContextListener used to bootstrap it):
public class DateTimeFormatAwareElResolver extends ELResolver implements ServletContextListener {
private final ThreadLocal<Boolean> isGetValueInProgress = new ThreadLocal<>();
#Override
public void contextInitialized(ServletContextEvent event) {
JspFactory.getDefaultFactory().getJspApplicationContext(event.getServletContext()).addELResolver(this);
}
#Override
public void contextDestroyed(ServletContextEvent sce) {}
#Override
public Object getValue(ELContext context, Object base, Object property) {
try {
if (Boolean.TRUE.equals(isGetValueInProgress.get())) {
return null;
}
isGetValueInProgress.set(Boolean.TRUE);
Object value = context.getELResolver().getValue(context, base, property);
if (value != null && isFormattableDate(value)) {
String pattern = getDateTimeFormatPatternOrNull(base, property.toString());
if (pattern != null) {
return format(value, DateTimeFormatter.ofPattern(pattern));
}
}
return value;
}
finally {
isGetValueInProgress.remove();
}
}
private boolean isFormattableDate(Object value) {
return value instanceof LocalDate || value instanceof LocalDateTime;
}
private String format(Object localDateOrLocalDateTime, DateTimeFormatter formatter) {
if (localDateOrLocalDateTime instanceof LocalDate) {
return ((LocalDate)localDateOrLocalDateTime).format(formatter);
}
return ((LocalDateTime)localDateOrLocalDateTime).format(formatter);
}
private String getDateTimeFormatPatternOrNull(Object base, String property) {
DateTimeFormat dateTimeFormat = getDateTimeFormatAnnotation(base, property);
if (dateTimeFormat != null) {
return dateTimeFormat.pattern();
}
return null;
}
private DateTimeFormat getDateTimeFormatAnnotation(Object base, String property) {
DateTimeFormat dtf = getDateTimeFormatFieldAnnotation(base, property);
return dtf != null ? dtf : getDateTimeFormatMethodAnnotation(base, property);
}
private DateTimeFormat getDateTimeFormatFieldAnnotation(Object base, String property) {
try {
if (base != null && property != null) {
Field field = base.getClass().getDeclaredField(property);
return field.getAnnotation(DateTimeFormat.class);
}
}
catch (NoSuchFieldException | SecurityException ignore) {
}
return null;
}
private DateTimeFormat getDateTimeFormatMethodAnnotation(Object base, String property) {
try {
if (base != null && property != null) {
Method method = base.getClass().getMethod("get" + StringUtils.capitalize(property));
return method.getAnnotation(DateTimeFormat.class);
}
}
catch (NoSuchMethodException ignore) {
}
return null;
}
#Override
public Class<?> getType(ELContext context, Object base, Object property) {
return null;
}
#Override
public void setValue(ELContext context, Object base, Object property, Object value) {
}
#Override
public boolean isReadOnly(ELContext context, Object base, Object property) {
return true;
}
#Override
public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base) {
return null;
}
#Override
public Class<?> getCommonPropertyType(ELContext context, Object base) {
return null;
}
}
Register the ELResolver in web.xml:
<listener>
<listener-class>com.company.el.DateTimeFormatAwareElResolver</listener-class>
</listener>
And now when I have ${widget.created} in my jsp, the value displayed will be formatted according to the #DateTimeFormat annotation!
Additionally, if the LocalDate or LocalDateTime object is needed by the jsp (and not just the formatted String representation), you can still access the object itself using direct method invocation like: ${widget.getCreated()}
I want convert json string to one object.
The json looks like this:
{"receive":1413342268310}
And the object is like:
public class PositionBean {
private Long id;
private Date receive;
public void setReceive (Date receive) {
this.receive = receive;
}
public void setReceive (Long receive) {
this.receive = new Date (receive);
}
public Long getReceive () {
return receive.getTime ();
}
}
All the set and get methods I have to use in other class, so I can't delete one method.
When I invoke
objectMapper.readValue(str, PositionBean.class);
It prompt exception, the jackon don't know which method set, so I use #JsonIgnore, but I found the receive is null.
You can use annotation #JsonSetter to specify which method should be used as setter.
Example:
public class PositionBean {
private Long id;
private Date receive;
public void setReceive (Date receive) {
this.receive = receive;
}
#JsonSetter
public void setReceive (Long receive) {
this.receive = new Date (receive);
}
public Long getReceive () {
return receive.getTime ();
}
}
When you mark setter (e.g. setXXX) with #JsonIgnore it means that property XXX will be ignored.
From documentation:
For example, a "getter" method that would otherwise denote a property
(like, say, "getValue" to suggest property "value") to serialize,
would be ignored and no such property would be output unless another
annotation defines alternative method to use.
You can also use
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
This will not throw any mapping exception even if u dont have an appropriate field in the mapping class corresponding to a JSON field. Once configured u can use ur code for further processing.
objectMapper.readValue (str, PositionBean.class);