7

I have the next couple of beans:

Address { String name; String number; String zipcode; String town; } MyEntity { Address address; String value1; String value2; } 

I'm trying to do the next Hibernate query:

private final List<String> propertiesDistinct = Arrays.asList("address.name"); private final List<String> properties = Arrays.asList("address.number", "address.zipcode", "address.town") ProjectionList projectionList = Projections.projectionList(); if (propertiesDistinct != null) { ProjectionList projectionListDistinct = Projections.projectionList(); for (String propertyDistinct : propertiesDistinct) projectionListDistinct.add(Projections.property(propertyDistinct).as(propertyDistinct)); projectionList.add(Projections.distinct(projectionListAgrupar)); } if (properties != null) for (String property : properties) projectionList.add(Projections.property(property).as(property)); criterio.setProjection(projectionList); // MORE FILTERS ON MyEntity FIELDS //... criterio.add(Restrinctions...); // I want to recover the results on my bean MyEntity so I don't have to create a new one criterio.setResultTransformer(Transformers.aliasToBean(MyEntity.class)); 

Problem:

Caused by: org.hibernate.PropertyNotFoundException: Could not find setter for address.name on class com.entities.MyEntity 

I understand that Hibernate is looking for something like:

public String getAddressName() {} // This should be in MyEntity 

Instead of:

public String getName() {} // In my Address bean 

Ideas about how can I fix this without creating a new bean?

Thanks!

2
  • Do you have setAddress(Address address) in MyEntity and all other setters in all beans? Commented Sep 10, 2013 at 7:49
  • @bellabax yes I do :) Commented Sep 10, 2013 at 7:53

5 Answers 5

22

I wrote a ResultTransformer that can fix your problem. It's name is AliasToBeanNestedResultTransformer, check it out on github.

Sign up to request clarification or add additional context in comments.

2 Comments

Sami Andoni this is exactly what I was looking for! Thank you very much. Great Transformer :)
@Sami Andoni: can you give some guideline to develop it for collection (OneToMany relationship)?
3

Code provided in Github works fine but there is change in import for new versions of hibernate. Its as follow.

org.hibernate.property.PropertyAccessor replaced byorg.hibernate.property.access.spi.PropertyAccess

and

org.hibernate.property.PropertyAccessorFactory replaced by org.hibernate.property.access.internal.PropertyAccessStrategyBasicImpl

So you'll have change the code from

PropertyAccessor accessor = PropertyAccessorFactory.getPropertyAccessor("property"); accessor.getSetter(resultClass, (String)subclassToAlias.get(subclass).get(2)).set(root, subObject, null); 

to

PropertyAccess propertyAccess = PropertyAccessStrategyBasicImpl.INSTANCE.buildPropertyAccess(resultClass, (String)subclassToAlias.get(subclass).get(2)); propertyAccess.getSetter().set(root, subObject, null); 

Comments

2

AliasToBeanNestedResultTransformer does not handle Nested Multi Level DTOs, so I rewrote one that handles n-level dtos.

Hope this helps.

public class AliasToBeanNestedMultiLevelResultTransformer extends AliasedTupleSubsetResultTransformer { private static final long serialVersionUID = -8047276133980128266L; public boolean isTransformedValueATupleElement(String[] aliases, int tupleLength) { return false; } private boolean initialized; private Class<?> resultClass; private Map<String,Class<?>> clazzMap = new HashMap<>(); private Map<String,Setter> settersMap = new HashMap<>(); public AliasToBeanNestedMultiLevelResultTransformer(Class<?> resultClass) { this.resultClass = resultClass; } public Object transformTuple(Object[] tuples, String[] aliases) { Map<String,Object> nestedObjectsMap = new HashMap<>(); Object result; try { result = resultClass.newInstance(); if (!initialized){ initialized = true; initialize(aliases); } for (int a=0;a<aliases.length;a++){ String alias = aliases[a]; Object tuple = tuples[a]; Object baseObject = result; int index = alias.lastIndexOf("."); if(index>0){ String basePath = alias.substring(0, index); baseObject = nestedObjectsMap.get(basePath); if (baseObject == null){ baseObject = clazzMap.get(basePath).newInstance(); nestedObjectsMap.put(basePath, baseObject); } } settersMap.get(alias).set(baseObject, tuple,null); } for (Entry<String,Object> entry:nestedObjectsMap.entrySet()){ Setter setter = settersMap.get(entry.getKey()); if (entry.getKey().contains(".")){ int index = entry.getKey().lastIndexOf("."); String basePath = entry.getKey().substring(0, index); Object obj = nestedObjectsMap.get(basePath); setter.set(obj, entry.getValue(), null); } else{ setter.set(result, entry.getValue(), null); } } }catch ( InstantiationException | IllegalAccessException e) { throw new HibernateException( "Could not instantiate resultclass: " + resultClass.getName() ); } return result; } private void initialize(String[] aliases) { PropertyAccessor propertyAccessor = new ChainedPropertyAccessor( new PropertyAccessor[] { PropertyAccessorFactory.getPropertyAccessor( resultClass, null ), PropertyAccessorFactory.getPropertyAccessor( "field" ) } ); for (int a=0;a<aliases.length;a++){ String alias = aliases[a]; Class<?> baseClass = resultClass; if (alias.contains(".")){ String[] split = alias.split("\\."); StringBuffer res = new StringBuffer(); for (int i=0;i<split.length;i++){ if (res.length()>0) res.append("."); String item = split[i]; res.append(item); String resString = res.toString(); if (i==split.length-1){ clazzMap.put(resString,baseClass); settersMap.put(resString, propertyAccessor.getSetter(baseClass, item)); break; } Class<?> clazz = clazzMap.get(resString); if (clazz==null){ clazz = propertyAccessor.getGetter(baseClass,item).getReturnType(); settersMap.put(resString, propertyAccessor.getSetter(baseClass, item)); clazzMap.put(resString,clazz); } baseClass = clazz; } } else{ clazzMap.put(alias, resultClass); settersMap.put(alias, propertyAccessor.getSetter(resultClass, alias)); } } } 

}

1 Comment

you can add after Object tuple = tuples[a]; if (tuple == null) continue;
2

My solution is very basic. It's not as clean as a proper result transformer but it's useful when you just need to do a quick projection for a few properties.

If you get Could not find setter for address.name on class com.entities.MyEntity

It doesn't mean Hibernate is looking for public String getAddressName() {}. Instead it looks for a setter with the impossible "setAddress.name" name.

Instead of .add(Projections.property("address.name"),"address.name")) type a proper setter name as second argument to the .add() method as follows .add(Projections.property("address.name"),"addressName"))

Then, just add a setter on your "MyEntity" root object: "setAddressName".

public void setAddressName(String addressName) { this.address= (this.address==null) ? new Address() : address; this.address.setName(addressName); } 

The drawback is that it "dirties" your object with extra methods.

Also posted here.

1 Comment

I tried this approach and it fails with: javax.persistence.PersistenceException: org.hibernate.PropertyNotFoundException: Could not resolve PropertyAccess for addressName on class <class>. It works if I also define a public String getAddressName(), but I do not want to have the getter. I'm using Hibernate 5.3.18.
1

Try creating an alias like criterio.createAlias("address", "add"); and then edit your properties to be like Arrays.asList("add.number","add.zipcode", "add.town").

Hope this helps.

4 Comments

I tried your solution but I got the next exception: org.hibernate.QueryException: Criteria objects cannot be created directly on components. Create a criteria on owning entity and use a dotted property to access component property: address
Try createCriteria instead of createAlias. I can't test myself.
Are you adding your projections to new criteria? Note that createCriteria returns an instance of Criteria. You should set your projections to this new one.
Ean thanks for your help, I sholved it with Sami Andoni transformer. Thank you anyway for your time :)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.