java - How to group by projections with Hibernate -


i need find list of students in specific group , located in specific address along phone numbers in location.

my main issue can not retrieve phone numbers of each student collection. example if have student1,student2. phone 1111 student1 in location1 , phone 2222 , phone 3333 student2 in location 1 , phone 444 student2 in location2.

lets have

student1 alex group1 1111 location1 street1 student3 jack group1 93939 location2 street4 student7 joe group2 22223 location4 street8 student2 john group1 2222 3333 location1 street1 student2 john group1 4444 location1 street2 student12 mark group1 4423 location9 street9 

sample output data

 user asks students in group1 , location1   student1 alex street1 phone 1111 distance30 student2 john street1 phones 22222,3333 distance30 student2 john street2 phone 4444 distance40 

in other words, have list of students along locations , phones of selected location.

hibernate returns following error message against current code

org.springframework.orm.hibernate4.hibernatesystemexception:  illegalargumentexception occurred while calling setter property  [com.example.address.phones (expected type = java.util.list)]; target  = [com.example.results.allstudents@6deeac0], property value =  [11111111] setter of com.example.results.allstudents.phones; nested  exception illegalargumentexception occurred while calling setter  property [com.example.results.allstudents.phones (expected type =  java.util.list)]; target = [com.example.results.allstudents@6deeac0],  property value = [11111111] 

student

@entity public class student implements java.io.serializable {      private static final long serialversionuid = -23949494858373847l;     @id     @generatedvalue     string id;     string name;     @manytomany(fetch = fetchtype.lazy, cascade = cascadetype.all)     @jointable(name = "student_groups", joincolumns = { @joincolumn(name = "id", nullable = false, updatable = false) }, inversejoincolumns = { @joincolumn(name = "groupid", nullable = false, updatable = false) })     set<group> groups = new hashset<group>(0);     .. } 

address

@entity public class address implements java.io.serializable {      private static final long serialversionuid = -274634747474623637l;     @id     @generatedvalue     string addid;     @id     @manytoone     @joincolumn(name = "id", nullable = false)     student student;     @manytoone     @joincolumn(name = "locid", nullable = false)     location location;     double latitude;     double longitude;     string address;     @onetomany(mappedby = "phoneowner", fetch = fetchtype.eager)     set<phone> phones = new hashset<phone>();           string formula = "( 6371 * acos ( cos ( radians("                 + lat                 + ") ) * cos( radians( this_.latitude ) ) * cos( radians( this_.longitude ) - radians("                 + lan + ") ) +" + "sin ( radians(" + lat                 + ") ) * sin( radians( this_.latitude ) ) ) ) distance";         session session = sessionfactory.getcurrentsession();         projectionlist pl = projections                 .projectionlist()                 .add(projections.property("std.id").as("id"))                 .add(projections.property("std.name").as("name"))                 .add(projections.property("addr.address").as(                         "address"))                 .add(projections.property("location.name").as("location"))                 .add(projections.property("location.city").as("city"))                 .add(projections.property("location.latitude").as("latitude"))                 .add(projections.property("location.longitude").as("longitude"))                 .add(projections.sqlprojection(formula,                         new string[] { "distance" },                         new type[] { new doubletype() }));          list<allstudents> students = (list<allstudents) session                 .createcriteria(address.class, "addr")                 .createalias("addr.student", "std")                 .createalias("std.groups", "group")                 .createalias("addr.location", "location")                 .setprojection(pl)                 .setfetchmode("group", fetchmode.join)                 .add(restrictions.ilike("group.name", groupname))                 .add(restrictions.eq("location.id", locid))                 .setresulttransformer(                         new aliastobeannestedresulttransformer(allstudents.class))                 .list(); 

results class

public class allstudents {    list<string> phones;    ... } 

aliastobeannestedresulttransformer

public class aliastobeannestedresulttransformer extends aliasedtuplesubsetresulttransformer {      private static final long serialversionuid = -8047276133980128266l;      private static final int tupe_index = 0;     private static final int alises_index = 1;     private static final int fieldname_index = 2;      private static final propertyaccessor accessor = propertyaccessorfactory             .getpropertyaccessor("property");      private final class<?> resultclass;      private object[] entitytuples;     private string[] entityaliases;      private map<string, class<?>> fieldtoclass = new hashmap<string, class<?>>();     private map<string, list<?>> subentities = new hashmap<string, list<?>>();     private list<string> nestedaliases = new arraylist<string>();     private map<string, class<?>> listfields = new hashmap<string, class<?>>();      public boolean istransformedvalueatupleelement(string[] aliases,             int tuplelength) {         return false;     }      public aliastobeannestedresulttransformer(class<?> resultclass) {          this.resultclass = resultclass;     }      public object transformtuple(object[] tuple, string[] aliases) {          handlesubentities(tuple, aliases);         cleanparams(tuple, aliases);         resulttransformer roottransformer = new aliastobeanresulttransformer(                 resultclass);         object root = roottransformer.transformtuple(entitytuples,                 entityaliases);          loadsubentities(root);          cleanmaps();         return root;     }      private void handlesubentities(object[] tuple, string[] aliases)             throws hibernateexception {         string fieldname = "";         string aliasname = "";         try {             (int = 0; < aliases.length; i++) {                 string alias = aliases[i];                 if (alias.contains(".")) {                      string[] sp = alias.split("\\.");                     stringbuilder aliasbuilder = new stringbuilder();                     (int j = 0; j < sp.length; j++) {                         if (j == 0) {                             fieldname = sp[j];                         } else {                             aliasbuilder.append(sp[j]);                             aliasbuilder.append(".");                         }                     }                     aliasname = aliasbuilder.substring(0,                             aliasbuilder.length() - 1);                      nestedaliases.add(alias);                     manageentities(fieldname, aliasname, tuple[i]);                 }             }         } catch (nosuchfieldexception e) {             throw new hibernateexception("could not instantiate resultclass: "                     + resultclass.getname() + " field name: " + fieldname                     + " , alias name:" + aliasname);         }     }      private class<?> findclass(string fieldname) throws nosuchfieldexception,     securityexception {         if (fieldtoclass.containskey(fieldname)) {             return fieldtoclass.get(fieldname);         } else {             class<?> subclass = resultclass.getdeclaredfield(fieldname)                     .gettype();              if (subclass.equals(list.class) || subclass.equals(set.class)) {                 if (subclass.equals(list.class)) {                     listfields.put(fieldname, linkedlist.class);                 } else {                     listfields.put(fieldname, hashset.class);                 }                 field field = resultclass.getdeclaredfield(fieldname);                 parameterizedtype generictype = (parameterizedtype) field                         .getgenerictype();                 subclass = (class<?>) generictype.getactualtypearguments()[0];              }             fieldtoclass.put(fieldname, subclass);             return subclass;         }     }      @suppresswarnings("unchecked")     private void manageentities(string fieldname, string aliasname,             object tuplevalue) throws nosuchfieldexception, securityexception {         class<?> subclass = findclass(fieldname);         if (!subentities.containskey(fieldname)) {             list<object> list = new arraylist<object>();             list.add(new arraylist<object>());             list.add(new arraylist<string>());             list.add(fieldname_index, subclass);             subentities.put(fieldname, list);         }         ((list<object>) subentities.get(fieldname).get(tupe_index))         .add(tuplevalue);         ((list<string>) subentities.get(fieldname).get(alises_index))         .add(aliasname);     }      private void cleanparams(object[] tuple, string[] aliases) {         entitytuples = new object[aliases.length - nestedaliases.size()];         entityaliases = new string[aliases.length - nestedaliases.size()];          (int j = 0, = 0; j < aliases.length; j++) {             if (!nestedaliases.contains(aliases[j])) {                 entitytuples[i] = tuple[j];                 entityaliases[i] = aliases[j];                 ++i;             }         }     }      @suppresswarnings({ "unchecked", "rawtypes" })     private void loadsubentities(object root) throws hibernateexception {         try {             (string fieldname : subentities.keyset()) {                 class<?> subclass = (class<?>) subentities.get(fieldname).get(                         fieldname_index);                  resulttransformer subclasstransformer = new aliastobeannestedresulttransformer(                         subclass);                  object subobject = subclasstransformer.transformtuple(                         ((list<object>) subentities.get(fieldname).get(0))                         .toarray(),                         ((list<object>) subentities.get(fieldname).get(1))                         .toarray(new string[0]));                  setter setter = accessor.getsetter(resultclass, fieldname);                 if (listfields.containskey(fieldname)) {                     class<?> collectionclass = listfields.get(fieldname);                     collection subobjectlist = (collection) collectionclass                             .newinstance();                     subobjectlist.add(subobject);                     setter.set(root, subobjectlist, null);                 } else {                     setter.set(root, subobject, null);                 }             }         } catch (exception e) {             throw new hibernateexception(e);         }     }      private void cleanmaps() {         fieldtoclass = new hashmap<string, class<?>>();         subentities = new hashmap<string, list<?>>();         nestedaliases = new arraylist<string>();         listfields = new hashmap<string, class<?>>();     }  } 

the aliastobeannestedresulttransformer supports nested dtos doesn not support collections of dtos.

you can change allstudent dts to:

public class allstudents {     student student;     string phone;     location location;      public allstudents(student student, string phone, location location) {         this.student = student;         this.phone = phone;         this.location = location;     }      public student getstudent() {         return student;     }      public string getphone() {         return phone;     }      public location getlocation() {         return location;     } } 

and need add studentdto hold aggregation result:

public class studentdto {     private final student student;     private string location;     private list<string> phones = new arraylist<>();      public studentdto(student student) {         this.student = student;     }      public student getstudent() {         return student;     }      public string getlocation() {         return location;     }      public void setlocation(string location) {         this.location = location;     }      public list<string> getphones() {         return phones;     } } 

now when run query list of allstudents:

list<allstudents> allstudents = ... 

which group this:

linkedhashmap<long, studentdto> studentmap = new linkedhashmap<>();  for(allstudents : allstudents) {     studentdto studentdto = studentmap.get(all.getstudent().getid());     if(studentdto == null) {         studentdto = new studentdto(all.getstudent());         studentmap.put(all.getstudent().getid(), studentdto);     }     if(all.getphone() != null) {         studentdto.getphones().add(all.getphone());     }     studentdto.setlocation(all.getlocation()); }  list<studentdto> studentdtos = new arraylist<>(studentmap.values()); 

Comments