I know how to preselect <p:selectOneMenu>, in selected value should be one of the objects from <f:selectItems>, but how does this component work under the hood and can I change this behavior?
In my case I've a duplicate object, actually this is two objects with the same values but created twice and selected object in <p:selectOneMenu> differs from object from <f:selectItems> and it doens't recognize it.
Most likely I will change my design so, it will point to same object but in case I can't do it due to legacy code or etc, how can I change the behavior of <p:selectOneMenu> that it will compare objects by id for example?
I'd thought that converter responsible for it, but when it rendered it doesn't enter on getAsObject method only getAsString, so I guess that there's something different, but what?
Thank you
It uses Object#equals() for that. You can change (fix) this behavior by implementing it accordingly on your entity.
private Long id;
#Override
public boolean equals(Object other) {
return (other != null && getClass() == other.getClass() && id != null)
? id.equals(getClass().cast(other).id)
: (other == this);
}
Don't forget the hashCode() to satisfy the equals-hashCode contract.
#Override
public int hashCode() {
return (id != null)
? (getClass().hashCode() + id.hashCode())
: super.hashCode();
}
If you can't change the existing entity for some unclear reason, wrap it in your own DTO.
The converter only converts between the entity and its unique String representation for usage in HTML output and HTTP request parameters and has therefore no influence on preselection. It has only influence on potential Validation Error: Value is not valid trouble.
See also:
How to populate options of h:selectOneMenu from database?
Related
In my topbar I have a <o:graphicImage> to show picture from my user.
<o:graphicImage dataURI="true" height="32" width="32" styleClass="img-circle"
value="#{employeeProfileMenuPictureRequestController.getPicture_32_32(loginBean.currentEmployee)}"
lastModified="#{employeeProfileMenuPictureRequestController.lastUpdate}" />
My backend bean is the following:
#GraphicImageBean
public class EmployeeProfileMenuPictureRequestController implements Serializable {
private Date lastUpdate = new Date();
public byte[] getPicture_32_32(Employee employee) throws StorageAttachmentNotFoundException, IOException {
try {
String path = employeeProfilePictureService.findProfileImageByEmployee(employee, FileSizeType.SIZE_32_32.toString());
if (employee == null || path == null || path.isEmpty()) {
return Utils.toByteArray(Faces.getResourceAsStream("/resources/images/no-photo-icon.png"));
}
Path fileLocation = Paths.get(path);
byte[] data = Files.readAllBytes(fileLocation);
LOGGER.info("END getPicture_32_32");
return data;
catch (Exception e) {
LOGGER.error(ExceptionUtils.getFullStackTrace(e));
}
return Utils.toByteArray(Faces.getResourceAsStream("/resources/images/no-photo-icon.png"));
}
public Date getLastUpdate() {
return lastUpdate;
}
}
Unfortunatelly the getPicture_32_32(Employee) is called for every page request / page navigation. This means it´s also everytime a request against the database, which takes time.
I´ve tried already to add lastModified to the <o:graphicImage>, but the function is called also everytime for each page request.
Can anybody help me to solve this?
According to <o:graphicImage> documentation:
Data URI
[...]
This approach is however not recommended for "permanent" and/or "large" images as it doesn't offer the browser any opportunity to cache the images for reuse, ~10KB would typically be the max even less so if there are more such images on the same page.
So, it does not support caching at all. The technical reason is that it basically embeds whole contents of the image in the HTML output. It does not embed an URL to the image. The lastModified is basically ignored. I should probably better document that. At least, you should absolutely remove the dataURI attribute. It's only useful for e.g. preview of an uploaded image.
And,
Image streaming
[...]
In case the property is a method expression taking arguments, each of those arguments will be converted to a string HTTP request parameter and back to actual objects using the converters registered by class as available via Application.createConverter(Class). So, most of standard types like Long are already implicitly supported. In case you need to supply a custom object as argument for some reason, you need to explicitly register a converter for it yourself via #FacesConverter(forClass).
So, because your method take a Employee argument, you basically need to have a #FacesConverter(forClass=Employee.class) so that JSF can automatically convert it from and to String. How to create converters can be found here: Conversion Error setting value for 'null Converter' - Why do I need a Converter in JSF?
You should end up with something like this:
#FacesConverter(forClass=Employee.class)
public class EmployeeConverter implements Converter {
#Override
public String getAsString(FacesContext context, UIComponent component, Object modelValue) {
// Write code here which converts Employee to its unique String representation.
}
#Override
public Object getAsObject(FacesContext context, UIComponent component, String submittedValue) {
// Write code here which coverts the Employee unique String representation
// as created in above method back to the original Employee object.
}
}
An alternative is to adjust your getPicture_32_32() method to take employee ID as e.g. Long instead of employee. Then you don't need a custom converter. JSF has already a built-in converter for Long.
public byte[] getPicture_32_32(Long employeeId) {
// ...
}
<o:graphicImage
value="#{employeeProfileMenuPictureRequestController.getPicture_32_32(loginBean.currentEmployee.id)}" />
Coming back to caching, the documentation says this:
Caching
[...]
When unspecified, then the "default resource maximum age" as set in either the Mojarra specific context parameter com.sun.faces.defaultResourceMaxAge or MyFaces specific context parameter org.apache.myfaces.RESOURCE_MAX_TIME_EXPIRES will be used, else a default of 1 week will be assumed.
So, when you have no resource age settings, it's already by default cached for 1 week. The lastModified is thus optional and only useful when you actually track a timestamp in the same database or filesystem when the image is actually changed. You should then really use that instead for most optimal caching. A "random" date is absolutely not the correct way.
I know how to preselect <p:selectOneMenu>, in selected value should be one of the objects from <f:selectItems>, but how does this component work under the hood and can I change this behavior?
In my case I've a duplicate object, actually this is two objects with the same values but created twice and selected object in <p:selectOneMenu> differs from object from <f:selectItems> and it doens't recognize it.
Most likely I will change my design so, it will point to same object but in case I can't do it due to legacy code or etc, how can I change the behavior of <p:selectOneMenu> that it will compare objects by id for example?
I'd thought that converter responsible for it, but when it rendered it doesn't enter on getAsObject method only getAsString, so I guess that there's something different, but what?
Thank you
It uses Object#equals() for that. You can change (fix) this behavior by implementing it accordingly on your entity.
private Long id;
#Override
public boolean equals(Object other) {
return (other != null && getClass() == other.getClass() && id != null)
? id.equals(getClass().cast(other).id)
: (other == this);
}
Don't forget the hashCode() to satisfy the equals-hashCode contract.
#Override
public int hashCode() {
return (id != null)
? (getClass().hashCode() + id.hashCode())
: super.hashCode();
}
If you can't change the existing entity for some unclear reason, wrap it in your own DTO.
The converter only converts between the entity and its unique String representation for usage in HTML output and HTTP request parameters and has therefore no influence on preselection. It has only influence on potential Validation Error: Value is not valid trouble.
See also:
How to populate options of h:selectOneMenu from database?
I have gone through this, but the answer is not very clear to me. Hence asking,
For the validate method of the class UIInput, we have this (Marking only those lines which are related to the question)
public void validate(FacesContext context) {
Object submittedValue = getSubmittedValue(); // LINE 958
newValue = getConvertedValue(context, submittedValue); // LINE 976
validateValue(context, newValue); // LINE 983
if (isValid()) { // LINE 987
Object previous = getValue();
setValue(newValue); // LINE 989
setSubmittedValue(null);
}
}
If both Conversion & Validation succeeds, then isValid() returns true.
The component's local value is then set - setValue(newValue), indicated by the flag setLocalValueSet(true)
After that, the submitted value is set to null - setSubmittedValue(null)
If you look at the code for this setValue(...) method of UIInput, it is overridden,
#Override
public void setValue(Object value) {
super.setValue(value);
// Mark the local value as set.
setLocalValueSet(true);
}
So from LINE 989, the call delegated to this above setValue(...).
If you look at this method,
#Override
public Object getValue() {
return isLocalValueSet() ? getLocalValue() : super.getValue();
}
If the local value was set by setValue(...), indicated by the flag setLocalValueSet(true),
why is this returning the getLocalValue()?
I mean,
isLocalValueSet() ? getLocalValue() : ....
Why is it not
isLocalValueSet() ? getValue() : ....
As seen through above, my confusion is regarding getValue() & getLocalValue() methods. Furthermore, in which case Object previous = getValue(); will be not null?
If the local value was set by setValue(...), indicated by the flag setLocalValueSet(true), why is this returning the getLocalValue()?
I think it's helpful to read javadoc of ValueHolder interface.
Object getLocalValue()
Return the local value of this UIComponent (if any), without evaluating any associated ValueExpression.
Object getValue()
Gets the value of this UIComponent. If validation failed, as indicated by FacesContext.isValidationFailed() returning true, always return the local value. Otherwise, first, consult the local value property of this component. If non-null return it. If null, see if we have a ValueExpression for the value property. If so, return the result of evaluating the property, otherwise return null.
void setValue(Object value)
Set the value of this UIComponent (if any).
Note my emphasis on "without".
In other words, getLocalValue() and setValue() form a true getter/setter pair, basically referring component's own instance variable, not the bean property behind any expression specified in component's value attribute such as value="#{bean.value}".
The getValue() method is implemented in such way that it auto-evaluates any associated ValueExpression when validation hasn't failed (yet) and the local value is null. This is undesireable when the (converted) submitted value is actually null and the component is still busy processing the validations phase and the model values haven't been updated yet.
Simply put, if getValue() were used instead of getLocalValue(), then the case "user removed (non-required) input value" would fail as getValue() returns the initial model value.
Furthermore, in which case Object previous = getValue(); will be not null?
When there's an initial value in the model.
There are a lot of workarounds for the missing support of enumerations in the Entity Framework 4.0. From all of them I like this one at most:
http://blogs.msdn.com/b/alexj/archive/2009/06/05/tip-23-how-to-fake-enums-in-ef-4.aspx?PageIndex=2#comments
This workaround allows you to use enums in your LINQ queries which is what i exactly need. However, I have a problem with this workaround. I get for every complex type I'm using a new partial autogenerated class.Therefore the code does not compile any more because I already have a wrapper class with this name in the same namespace which converts betwen the backed integer in the database and the enum in my POCO classes. If I make my wrapper a partial class, the code still does not compile as it now contains two properties with the same name "Value". The only possibility is to remove the Value property by hand everytime I generate the POCO classes because the DB model changed (which during the development phase happens very often).
Do you know how to prevent a partial class to be generated out of complex property everytime the EF model changes?
Can you recommend me some other workarounds supporting enumerations in LINQ queries?
That workaround is based on the fact that you are writing your POCO classes yourselves = no autogeneration. If you want to use it with autogeneration you must heavily modify T4 template itself.
Other workaround is wrapping enum conversion to custom extension methods.
public static IQueryable<MyEntity> FilterByMyEnum(this IQueryable<MyEntity> query, MyEnum enumValue)
{
int val = (int)enumValue;
return query.Where(e => e.MyEnumValue == val);
}
You will then call just:
var data = context.MyEntitites.FilterByMyEnum(MyEnum.SomeValue).ToList();
I am using an approach based on the one described in your link without any modifications of the T4 templates. The contents of my partial wrapper classes are as follows:
public partial class PriorityWrapper
{
public Priority EnumValue
{
get
{
return (Priority)Value;
}
set
{
Value = (int)value;
}
}
public static implicit operator PriorityWrapper(Priority value)
{
return new PriorityWrapper { EnumValue = value };
}
public static implicit operator Priority(PriorityWrapper value)
{
if (value == null)
return Priority.High;
else
return value.EnumValue;
}
}
I've only changed that instead of a back store variable with enum value I am using the autogenerated int typed Value property. Consequently Value can be an auto-implemented property and EnumValue property needs to do the conversion in getter and setter methods.
I have an input (JSF) that should be bound to a property in my bean. This property represents another bean and has an auxiliar method that checks if it's null (I use this method a lot).
The problem is that the binding is failing to get the proper getter and setter. Instead of reading the method that returns the bean, it reads the one that return a boolean value.
The property name is guest. The methods are:
getGuest;
setGuest;
isGuest (checks if guest is null).
JSF is trying to bind the object to isGuest and setGuest, instead of getGuest and setGuest.
I cannot rename isGuest to guestIsNull or something, because that would'nt make to much sense (see the class below).
Finally, my question is: how can I bind this property to the object without renaming my methods? Is it possible?
I also accept suggestions of a better method name (but the meaning must be the same).
Entity
#Entity
public class Passenger {
private Employee employee;
private Guest guest;
public Passenger() {
}
#Transient
public boolean isEmployee() {
return null != this.employee;
}
#Transient
public boolean isGuest() {
return null != this.guest;
}
#OneToOne
public Employee getEmployee() {
return this.employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
#OneToOne
public Guest getGuest() {
return this.guest;
}
public void setGuest(Guest guest) {
this.guest = guest;
}
}
JSF
<h:inputText value="#{passenger.employee}" />
<h:inputText value="#{passenger.guest}" />
Change the method name to isGuestNull.
The problem you're seeing is due to the fact that the EL lets you use getFoo or isFoo as the naming style for getter methods that return booleans.
No, that's not possible. You've to rename them.
Another way is to add a single getter returning an enum which covers all cases.
public enum Type {
GUEST, EMPLOYEE;
}
public Type getType() {
return guest != null ? Type.GUEST
: employee != null ? Type.EMPLOYEE
: null;
}
with
<h:something rendered="#{passenger.type == 'GUEST'}">
Binding to any property using any method is possible and quite easy if you create your custom ELResolver (apidocs). elresolvers are registered in faces config, and they are responsible, given an Object and a String defining a property, for determining the value and type of the given properties (and, as the need arises, to change it).
You could easily write your own ELResolver that would only work for your chosen, single type, and use (for example in a switch statement) the specific methods you need to write and read properties. And for other types it would delegate resolving up the resolver chain. It's really easy to do, much easier than it sounds.
But don't do it. The standard naming pattern of properties predates EL by many years. It is part of the JavaBeans™ standard - one of the very few undisputed standards in Javaland, working everywhere - from ant scripts, through spring configuration files to JSF. Seeing methods isPerson and getPerson in one class actually makes me fill uneasy, as it breaks something I always take for granted and can always count on.
If you like DDD and want to have your method's names pure, use an adapter. It's easy, fun, and gives a couple of additional lines, which is not something to sneer at if you get paid for the ammount of code produced:
public class MyNotReallyBean {
public String checkName() { ... }
public String lookUpLastName() { ... }
public String carefullyAskAboutAge() { ... }
public class BeanAdapter {
public String getName() { return checkName(); }
public String getLastName() { return lookUpLastName(); }
public String getAge() { return carefullyAskAboutAge(); }
}
private static BeanAdapter beanAdapter = new BeanAdapter();
private BeanAdapter getBeanAdapter(){ return beanAdapter; }
}