I am using the dynamic columns feature, provided by primefaces library. Because I also have nested properties (such as bean.city.address), I made a custom BeanElResolver to deal with that:
public class ExtendedBeanELResolver extends BeanELResolver {
#Override
public Object getValue(ELContext context, Object base, Object property)
throws NullPointerException, PropertyNotFoundException, ELException
{
if (property == null || base == null || base instanceof ResourceBundle || base instanceof Map || base instanceof Collection) {
return null;
}
String propertyString = property.toString();
if (propertyString.contains(".")) {
Object value = base;
for (String propertyPart : propertyString.split("\\.")) {
value = super.getValue(context, value, propertyPart);
}
return value;
}
else {
return super.getValue(context, base, property);
}
}
It works fine for the bean properties, but when the page is rendered I'm getting PropertyNotFound Exception for some image in primefaces, that is not a bean property:
Servlet failed with an Exception -javax.el.PropertyNotFoundException: The class 'org.primefaces.application.PrimeResourceHandler' does not have the property 'primefaces- aristo:images/ui-bg_highlight-soft_100_c4c4c4_1x100.png'.
I think that is because I extended the BeanELResolver class and it somehow overrides the default ELResolver, that deals with all sorts of properties. I tried to make a CompositeELResolver class, to deal with other types of properties as well, but I can't figure out how. Any ideas?
Related
I've got a bean that has a field of type List among other things.
public List<MyClass> getter() {
return field;
}
public void setter(MyClass[] source) {
this.field = Arrays.asList(source);
}
I've implemented a converter Converter<String, MyClass> and it works, too. If a string can be converted into MyClass, it's converted, and if not, an exception is thrown, and an instance of FieldError is included in Errors errors = binder.getBindingResult();. The problem is, the FieldError#getRejected method a String with a comma-separated list of both valid and invalid values, which can be misleading. And without a space, which is just ugly. Like this:
Field has invalid value of "valid,invalid"
while I would prefer
Field has invalid value of "invalid"
In other words, how to get the conversion and validation to work individually on each value?
Although spring's approach is not very intelligent, it's logically correct. The following code can help you find the invalid value.
FieldError fieldError = bindingResult.getFieldError();
if (fieldError != null && fieldError.contains(TypeMismatchException.class)) {
TypeMismatchException typeMismatchException = fieldError.unwrap(TypeMismatchException.class);
ConversionFailedException conversionFailedException = findConversionFailedException(typeMismatchException);
if (conversionFailedException != null) {
Object value = conversionFailedException.getValue();
// get the invalid field value
}
}
/**
* Recursively find the ConversionFailedException
* #param target
* #return
*/
public ConversionFailedException findConversionFailedException(Throwable target) {
Throwable cause = target.getCause();
if (cause == null) {
return null;
} else if (cause instanceof ConversionFailedException) {
return (ConversionFailedException)cause;
}
return findConversionFailedException(target);
}
I recently moved my spring application from java 1.6 to java 1.8. This has caused the spring bootstrapping to take an order of magnitude longer (20s before, 4mins now). Tracing the cause has led me to the CachedIntrospectionResults class, which is created for every bean. When created it calls,
beanInfo = (shouldIntrospectorIgnoreBeaninfoClasses ?
Introspector.getBeanInfo(beanClass, Introspector.IGNORE_ALL_BEANINFO) :
Introspector.getBeanInfo(beanClass));
Introspector then creates the bean info, in java 1.6, it calls
private BeanDescriptor getTargetBeanDescriptor() {
// Use explicit info, if available,
if (explicitBeanInfo != null) {
BeanDescriptor bd = explicitBeanInfo.getBeanDescriptor();
if (bd != null) {
return (bd);
}
}
// OK, fabricate a default BeanDescriptor.
return new BeanDescriptor(this.beanClass);
}
However in java 1.8 it now calls,
private BeanDescriptor getTargetBeanDescriptor() {
// Use explicit info, if available,
if (explicitBeanInfo != null) {
BeanDescriptor bd = explicitBeanInfo.getBeanDescriptor();
if (bd != null) {
return (bd);
}
}
// OK, fabricate a default BeanDescriptor.
return new BeanDescriptor(this.beanClass, findCustomizerClass(this.beanClass));
}
private static Class<?> findCustomizerClass(Class<?> type) {
String name = type.getName() + "Customizer";
try {
type = ClassFinder.findClass(name, type.getClassLoader());
// Each customizer should inherit java.awt.Component and implement java.beans.Customizer
// according to the section 9.3 of JavaBeans™ specification
if (Component.class.isAssignableFrom(type) && Customizer.class.isAssignableFrom(type)) {
return type;
}
}
catch (Exception exception) {
// ignore any exceptions
}
return null;
}
This method as far as I can see was added with java 1.7, and since I don't define any customizer classes, it searches my full classpath then throws an exception which ends up taking a few hundred ms. The result being that each bean takes ~500ms to init. A huge hit to startup time.
I am now trying to find a way to work around this problem,
The spring documentation says to implement a BeanInfoFactory in order to customize the beanInfo creation. But I can't find anywhere that says how to actaually create BeanInfo for a provided class.
How would I actually do that? Introspector uses a bunch of private constructors to build it up so I can't really follow it, and simply returning an empty BeanInfo blows spring up. What does spring actually want with the beaninfo?
Any ideas?
Normally, when you provide an explicit BeanInfo, the Introspector will gather information automatically whenever the explicit BeanInfo returns null. So there should be no problem providing an empty BeanInfo that only returns a non-null BeanDescriptor to prohibit the automatic Customizer search.
For example:
import java.beans.*;
import java.util.stream.Stream;
public class BeanInfoTest {
public static void main(String... arg) throws IntrospectionException {
BeanInfo bi=Introspector.getBeanInfo(TheComponent.class, Object.class);
System.out.println("properties: ");
Stream.of(bi.getPropertyDescriptors())
.map(p->p.getPropertyType().getSimpleName()+' '+p.getName())
.forEach(System.out::println);
}
public static class TheComponent {
String foo;
int bar;
public String getFoo() {
return foo;
}
public void setFoo(String foo) {
this.foo = foo;
}
public int getBar() {
return bar;
}
public void setBar(int bar) {
this.bar = bar;
}
}
public static class TheComponentBeanInfo extends SimpleBeanInfo {
/** Overridden to prevent the automated search for a Customizer */
#Override
public BeanDescriptor getBeanDescriptor() {
System.out.println("Providing my explicit BeanDescriptor");
return new BeanDescriptor(TheComponent.class);
}
}
}
will print
Providing my explicit BeanDescriptor
properties:
int bar
String foo
So it found the properties using automated search while using the explicit BeanDescriptor.
I'm currently revising a web application, and I have questions about data binding. I have a method that has been mapped with #RequestMapping, and in one of it's arguments I have a primitive integer type, something like this (the following code is basically a summary of my problem, not the actual code):
#RequestMapping(value = "/processSomething" , method = RequestMethod.GET)
public String processSomething(#ModelAttribute("myValue") int myValue)
{
// Do something with "myValue".
}
When I run the web application, i get the following:
HTTP Status 500 - Request processing failed; nested exception is
org.springframework.beans.BeanInstantiationException: Could not
instantiate bean class [int]: No default constructor found; nested
exception is java.lang.NoSuchMethodException: int.()
It makes me realize that data binding works only with objects. I tried to change int with Integer, but I ended up getting something very similar:
HTTP Status 500 - Request processing failed; nested exception is
org.springframework.beans.BeanInstantiationException: Could not
instantiate bean class [java.lang.Integer]: No default constructor
found; nested exception is java.lang.NoSuchMethodException:
java.lang.Integer.()
I know #ModelAttribute allows us to make data binding with the Spring MVC model, and if a model is not in there, it is created automatically by Spring and then it's returned. What am I doing wrong? What I forgot to do? Do I need to create a PropertyEditor for primitive types?
The funny thing is that it works perfectly with #RequestParam, but I would not want the user to see the value of my property in the URL.
NOTE: I'm currently using Spring Web MVC 4.1.1.RELEASE (with MAVEN)
UPDATE
I did what was suggested by tofindabhishek user. I created a class with the name Inteiro (translated as Integer), and I am using it as #ModelAttribute, just like this:
#RequestMapping(value = "/usuarios" , method = RequestMethod.GET)
public String getUsuarios(
Model model ,
#RequestParam("pag") int pagina ,
#ModelAttribute("total") Inteiro registros ,
#ModelAttribute("pesquisa") CriterioBuilder criterio ,
#ModelAttribute("id_sexo_f") Inteiro idSexF ,
#ModelAttribute("id_grupo_adm") Inteiro idGrpAdm )
{
// ...
}
The Inteiro class has basically just a single int primitive field with a public and empty constructor, and a set, get, equals and hashCode method. The previous problem appears to have been resolved, but when running my application, I came across this:
HTTP Status 500 - javax.el.ELException: Cannot convert
com.regra7.minhaapp.controle.wrap.Inteiro#3b of type class
com.regra7.minhaapp.controle.wrap.Inteiro to class java.lang.Long
Here's the Inteiro source code:
public class Inteiro
{
// #############################################################################################
// INSTĂ‚NCIAS
// #############################################################################################
private int valor;
// #############################################################################################
// CONSTRUTORES
// #############################################################################################
public Inteiro()
{
this.valor = 0;
}
// #############################################################################################
// MODIFICADORES
// #############################################################################################
public void set(int valor) { this.valor = valor; }
// #############################################################################################
// ACESSO
// #############################################################################################
public int get() { return this.valor; }
// #############################################################################################
// EQUALS E HASHCODE
// #############################################################################################
#Override
public boolean equals(Object o)
{
if (o == null)
{
return false;
}
else if (o == this)
{
return true;
}
else if (o.getClass() != this.getClass())
{
return false;
}
Inteiro inteiro = (Inteiro) o;
return inteiro.get() == valor;
}
#Override
public int hashCode()
{
return valor;
}
}
For what reason Spring is complaining that can not convert Inteiro to java.lang.Long? I'm not working with Long. Moreover... EL? That would mean "Expression Language", right? Does this have something to do with some of my JSP pages? I am trying to develop a JSP page that displays search results, and on this page I use EL. Is there any possibility to be a problem in my JSP page?
Thank you for your help.
public class ViewModel {
private Integer myValue;
}
Use Wrapper object(ViewModel) to capture your value and Bind ViewModel class as model attribute in this case you can handle null values by using Wrapper(Integer).if you don't want to handle null values you can use int.
public class ViewModel {
private int myValue;
}
I have a class and there are variables inside it as well. Sometimes I want to ignore some fields and sometimes not when deserializing (maybe at serializing too). How can I do it at Jackson?
For serialization, "filtering properties" blog entry should help. Deserialization side has less support, since it is more common to want to filter out stuff that is written.
One possible approach is to sub-class JacksonAnnotationIntrospector, override method(s) that introspect ignorability of methods (and/or fields) to use whatever logic you want.
It might also help if you gave an example of practical application, i.e what and why you are trying to prevent from being deserialized.
You might want to use JsonViews ( took it originally from http://wiki.fasterxml.com/JacksonJsonViews - broken now - web archive link: https://web.archive.org/web/20170831135842/http://wiki.fasterxml.com/JacksonJsonViews )
Quoting it:
First, defining views means declaring classes; you can reuse existing ones, or just create bogus classes -- they are just view identifiers with relationship information (child inherits view membership from parents):
// View definitions:
class Views {
static class Public { }
static class ExtendedPublic extends PublicView { }
static class Internal extends ExtendedPublicView { }
}
public class Bean {
// Name is public
#JsonView(Views.Public.class) String name;
// Address semi-public
#JsonView(Views.ExtendPublic.class) Address address;
// SSN only for internal usage
#JsonView(Views.Internal.class) SocialSecNumber ssn;
}
With such view definitions, serialization would be done like so:
// short-cut:
objectMapper.writeValueUsingView(out, beanInstance, ViewsPublic.class);
// or fully exploded:
objectMapper.getSerializationConfig().setSerializationView(Views.Public.class);
// (note: can also pre-construct config object with 'mapper.copySerializationConfig'; reuse)
objectMapper.writeValue(out, beanInstance); // will use active view set via Config
// or, starting with 1.5, more convenient (ObjectWriter is reusable too)
objectMapper.viewWriter(ViewsPublic.class).writeValue(out, beanInstance);
and result would only contain 'name', not 'address' or 'ssn'.
You should probably look at the modules feature of recent Jackson versions.
One possible mechanism would be to use a BeanDeserializerModifier.
I've been looking for a useful online tutorial or example, but nothing immediately appears. It might be possible to work something up if more is known of your context. Are you managing your ObjectMappers manually, or using them in a JAX-RS setting, injected in Spring, or what?
I searched the entire web (yes I did) to find the answer. then I wrote something on my own.
I'm working with Jackson ion deserialisation. I wrote a custom reader that ignores the fields dynamically.
You can do the same thing for json deserialisation.
Lets assume an entity like this.
User {
id
name
address {
city
}
}
Create a tree structure to represent field selection.
public class IonField {
private final String name;
private final IonField parent;
private final Set<IonField> fields = new HashSet<>();
// add constructs and stuff
}
Custom Ion Reader extending from amazon ion-java https://github.com/amzn/ion-java
public class IonReaderBinaryUserXSelective extends IonReaderBinaryUserX {
private IonField _current;
private int hierarchy = 0;
public IonReaderBinaryUserXSelective(byte[] data, int offset, int length,
IonSystem system, IonField _current) {
super(system, system.getCatalog(), UnifiedInputStreamX.makeStream(data, offset, length));
this._current = _current;
}
#Override
public IonType next() {
IonType type = super.next();
if (type == null) {
return null;
}
String file_name = getFieldName();
if (file_name == null || SystemSymbols.SYMBOLS.equals(file_name)) {
return type;
}
if (type == IonType.STRUCT || type == IonType.LIST) {
IonField field = _current.getField(getFieldName());
if (field != null) {
this._current = field;
return type;
} else {
super.stepIn();
super.stepOut();
}
return next();
} else {
if (this._current.contains(file_name)) {
return type;
} else {
return next();
}
}
}
#Override
public void stepIn() {
hierarchy = (hierarchy << 1);
if (getFieldName() != null && !SystemSymbols.SYMBOLS.equals(getFieldName())) {
hierarchy = hierarchy + 1;
}
super.stepIn();
}
#Override
public void stepOut() {
if ((hierarchy & 1) == 1) {
this._current = this._current.getParent();
}
hierarchy = hierarchy >> 1;
super.stepOut();
}
Construct dynamic view. This Tree dynamically created and passed to the reader to deserialise.
Let's say we only need city inside the address.
IonField root = new IonField("user", null);
IonField address = new IonField("address", root);
IonField city = new IonField("city", address);
address.addChild(city);
root.addChild(id);
//now usual stuff.
IonFactory ionFactory = new IonFactory();
IonObjectMapper mapper = new IonObjectMapper(ionFactory);
File file = new File("file.bin"); // ion bytes
byte[] ionData = Files.readAllBytes(file.toPath());
IonSystem ionSystem = IonSystemBuilder.standard().build();
IonReader ionReader = new IonReaderBinaryUserXSelective(ionData, 0, ionData.length, ionSystem, root);
User user = mapper.readValue(ionReader, User.class);
I'm using BeanUtils to manipulate Java objects created via JAXB, and I've run into an interesting issue. Sometimes, JAXB will create a Java object like this:
public class Bean {
protected Boolean happy;
public Boolean isHappy() {
return happy;
}
public void setHappy(Boolean happy) {
this.happy = happy;
}
}
The following code works just fine:
Bean bean = new Bean();
BeanUtils.setProperty(bean, "happy", true);
However, attempting to get the happy property like so:
Bean bean = new Bean();
BeanUtils.getProperty(bean, "happy");
Results in this exception:
Exception in thread "main" java.lang.NoSuchMethodException: Property 'happy' has no getter method in class 'class Bean'
Changing everything to a primitive boolean allows both the set and get call to work. I don't have this option, however, since these are generated classes. I assume this happens because the Java Bean libraries only consider an is<name> method to represent a property if the return type is a primitive boolean, and not the wrapper type Boolean. Does anyone have a suggestion as to how to access properties like these through BeanUtils? Is there some kind of workaround I can use?
Finally I've found legal confirmation:
8.3.2 Boolean properties
In addition, for boolean properties, we allow a getter method to match the pattern:
public boolean is<PropertyName>();
From JavaBeans specification. Are you sure you haven't came across JAXB-131 bug?
Workaround to handle Boolean isFooBar() case with BeanUtils
Create new BeanIntrospector
private static class BooleanIntrospector implements BeanIntrospector{
#Override
public void introspect(IntrospectionContext icontext) throws IntrospectionException {
for (Method m : icontext.getTargetClass().getMethods()) {
if (m.getName().startsWith("is") && Boolean.class.equals(m.getReturnType())) {
String propertyName = getPropertyName(m);
PropertyDescriptor pd = icontext.getPropertyDescriptor(propertyName);
if (pd == null)
icontext.addPropertyDescriptor(new PropertyDescriptor(propertyName, m, getWriteMethod(icontext.getTargetClass(), propertyName)));
else if (pd.getReadMethod() == null)
pd.setReadMethod(m);
}
}
}
private String getPropertyName(Method m){
return WordUtils.uncapitalize(m.getName().substring(2, m.getName().length()));
}
private Method getWriteMethod(Class<?> clazz, String propertyName){
try {
return clazz.getMethod("get" + WordUtils.capitalize(propertyName));
} catch (NoSuchMethodException e) {
return null;
}
}
}
Register BooleanIntrospector:
BeanUtilsBean.getInstance().getPropertyUtils().addBeanIntrospector(new BooleanIntrospector());
you can just create second getter with SET - sufix as workaround :)