Hi,
I've been working through the Hibernate Tutorials at
http://www.hibernate.org/hib_docs/v3/reference/en/html/tutorial.html
... And it took a bit of determined googling to find an answer to "How do I avoid those annoying (and worrisome) "warning: [unchecked] unchecked conversion" -Xlint compiler warnings
without sacrificing runtime type checking of collections returned by hibernate queries under java 1.6
Well, to save future newbies similar pain (and to show off a bit :-) here is an answer.
The interesting bit is the two wee helper methods at the bottom.
Code:
package events;
//http://www.hibernate.org/hib_docs/v3/reference/en/html/tutorial.html
//usage: ant run -Daction="" -Dtitle="" -Ddate="" -Dfirstname="" -Dlastname="" -Dage="" -Demail=""
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.Date;
import java.io.PrintStream;
import org.hibernate.Session;
import util.HibernateUtil;
public class EventManager {
//
// Test Harness
//
public static void main(String[] args) {
System.out.print("DEBUG: args=( "); for (String a : args) System.out.print(a + " "); System.out.println(")");
String action = args[0];
EventManager mgr = new EventManager();
//store an event
if ("storeEvent".equals(action)) {
System.out.println("Stored event " + mgr.createAndStoreEvent(args));
}
//store a person
else if ("storePerson".equals(action)) {
System.out.println("Stored person " + mgr.createAndStorePerson(args));
}
//store a person and an associated event
else if ("storePersonWithEvent".equals(action)) {
System.out.println("Stored " + mgr.createAndStorePersonWithEvent(args));
}
//associate an existing event with an existing person
else if ("addEventToPerson".equals(action)) {
System.out.println("Associated " + mgr.addEventToPerson(Long.parseLong(args[1]), Long.parseLong(args[2])));
}
//list the events
else if ("listEvents".equals(action)) {
mgr.printEvents(System.out);
}
//list the people (and there events)
else if ("listPeople".equals(action)) {
mgr.printPeople(System.out);
}
else {
System.err.println("Unknown action '" + action + "'");
}
HibernateUtil.closeSession();
}
//
// Events
//
private Event createEvent(String[] args) {
String title = getArg(args, 1, "title", "NOW");
Date date = Formatter.toDate(getArg(args, 2, "date", ""));
return new Event(date, title);
}
private Long storeEvent(Event event) {
Session s = HibernateUtil.getSession();
s.beginTransaction();
s.save(event);
s.getTransaction().commit();
return event.getId();
}
private Long createAndStoreEvent(String[] args) {
return storeEvent(createEvent(args));
}
private List <Event> listEvents() {
Session s = HibernateUtil.getSession();
s.beginTransaction();
List <Event> events = EventsList(s.createQuery("from Event").list());
s.getTransaction().commit();
return events;
}
private void printEvents(PrintStream out) {
for (Event e : listEvents()) {
out.println(e.toString());
}
}
//
// People
//
private Person createPerson(String[] args) {
String firstname = getArg(args, 3, "firstname", "Joe");
String lastname = getArg(args, 4, "lastname", "Bloggs");
int age = Integer.parseInt(getArg(args, 5, "age", "30"));
String email = getArg(args, 6, "email", null);
return new Person(firstname, lastname, age, email);
}
private Long storePerson(Person person) {
Session s = HibernateUtil.getSession();
s.beginTransaction();
s.save(person);
s.getTransaction().commit();
return person.getId();
}
private Long createAndStorePerson(String[] args) {
return storePerson(createPerson(args));
}
private List <Person> listPeople() {
Session s = HibernateUtil.getSession();
s.beginTransaction();
List <Person> people = PersonList(s.createQuery("from Person").list());
s.getTransaction().commit();
return people;
}
private void printPeople(PrintStream out) {
//p.getEvents() must be within a hibernate-transaction.
Session s = HibernateUtil.getSession();
s.beginTransaction();
List <Person> people = PersonList(s.createQuery("from Person").list());
for (Person p : people) {
out.println("## person: " + p.toString());
StringBuffer sb = new StringBuffer();
for (String e : p.getEmailAddresses()) {
sb.append(e + " ");
}
out.println("## email: " + sb);
for (Event e : p.getEvents()) {
out.println("## event: " + e.toString());
}
}
s.getTransaction().commit();
}
//
// email addresses
//
private void addEmailToPerson(Long personId, String emailAddress) {
Session s = HibernateUtil.getSession();
s.beginTransaction();
Person person = (Person) s.load(Person.class, personId);
// The getEmailAddresses() might trigger a lazy load of the collection
person.getEmailAddresses().add(emailAddress);
s.getTransaction().commit();
}
//
// Associate Events With People
//
private String createAndStorePersonWithEvent(String[] args) {
Long eventId = createAndStoreEvent(args);
Long personId = createAndStorePerson(args);
return addEventToPerson(personId, eventId);
}
private String addEventToPerson(Long personId, Long eventId) {
Session s = HibernateUtil.getSession();
s.beginTransaction();
Person person = (Person) s.load(Person.class, personId);
Event event = (Event) s.load(Event.class, eventId);
person.addEvent(event);
s.getTransaction().commit();
return("person " + personId + " with event " + eventId);
}
//
// Helper Functions
//
private static String getArg(String[] args, int i, String name, String dflt) {
return (args.length>i && !args[i].equals("${"+name+"}") ? args[i] : dflt);
}
private static void debug(String msg) {
if (true) System.err.println("DEBUG: " + msg);
}
//
// avoid those annoying "[unchecked] unchecked conversion" -Xlint compiler
// warnings whilst maintaining runtime type safety.... you'll get a
// ClassCastException if the unchecked List is not all Event objects, which
// is preferable to continuing blithely until we get an exception elsewhere.
//
// We do this in "helper methods" to localise the supression of unchecked
// warnings. This cannot be done with List<T> generics because you can't call
// <T>.class because type information is unavailable at runtime.
//
// The 1.5.0 javadoc for Collections.checkedList says:
// Returns a dynamically typesafe view of the specified list. Any attempt to
// insert an element of the wrong type will result in an immediate
// ClassCastException. Assuming a list contains no incorrectly typed elements
// prior to the time a dynamically typesafe view is generated, and that all
// subsequent access to the list takes place through the view, it is
// guaranteed that the list cannot contain an incorrectly typed element.
//
@SuppressWarnings("unchecked")
private static List<Event> EventsList(List unchecked) throws ClassCastException {
return Collections.checkedList(unchecked, Event.class);
}
@SuppressWarnings("unchecked")
private static List<Person> PersonList(List unchecked) throws ClassCastException {
return Collections.checkedList(unchecked, Person.class);
}
}
I'm no expert, so there very well may be a better solution. If you have one please post feel free ...
All cred should go to bruce and gafter at the sun forum
http://forum.java.sun.com/thread.jspa?threadID=487729&messageID=2291201
and the soupdragon at
http://forum.hibernate.org/viewtopic.php?t=939278&sid=3a16742f1cc60627da1a23a61fbcae75
Cheers. Keith.