I think I have hit a hibernate bug. I am running with hibernate debugging, so I can see this fine error in the logs:
Code:
2009-08-03 14:49:25,871 INFO [STDOUT] (http-127.0.0.1-8080-6) Hibernate: insert into AdtSessionModule (editDate, hwTypeId, manufacturerId, moduleId, adtSessionId, parentAdtSessionModuleId, serial, fwTypeId, fwVerId, hwVerId, oldFwTypeId, oldFwVerId, AdtSessionModuleTypeID, adtSessionModuleId) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'module', ?)
2009-08-03 14:49:25,872 INFO [org.hibernate.type.StringType] (http-127.0.0.1-8080-6) could not bind value '0618000377635b31' to parameter: 14; Invalid column index
2009-08-03 14:49:25,872 WARN [org.hibernate.util.JDBCExceptionReporter] (http-127.0.0.1-8080-6) SQL Error: 17003, SQLState: null
2009-08-03 14:49:25,872 ERROR [org.hibernate.util.JDBCExceptionReporter] (http-127.0.0.1-8080-6) Invalid column index
Notice how there are 13 question marks, but 14 values, because one is an enum that has been inserted directly. Looks like that is not accounted for when counting parameters.
The object in question looks like this:
Code:
@Entity
@Table(name = "AdtSessionModule")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "AdtSessionModuleTypeID",
discriminatorType = DiscriminatorType.STRING)
@IdClass(AdtSessionModulePk.class)
//Due to a bug in jdk 1.4+, Entities, which have a POJO ID class, cannot implement serializable.
public class AdtSessionModule //implements Serializable
{
protected AdtSessionModule() {
}
public enum Types {
METER("meter"),
MODULE("module");
String name;
private Types(String name){
this.name=name;
}
public String toString() {return name;}
}
/**
* The session in which this module was discovered.
*/
@ManyToOne
@JoinColumn(name = "adtSessionId", updatable = false, insertable = false)
private AdtSession session;
@Version
@Temporal(TemporalType.TIMESTAMP)
private Date editDate;
@Id
@Column(name="adtSessionModuleId", updatable = false, insertable = false)
private String adtSessionModuleId;
@Id
@Column(name="adtSessionId", updatable = false, insertable = false)
private long adtSessionId;
@OneToMany(mappedBy = "parentModule", cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH })
// @Transient
private Set<AdtSessionModule> children = new LinkedHashSet<AdtSessionModule>();
/**
* This module as it is discovered by the system. Null if the system has not
* discovered this module.
*/
@ManyToOne
@JoinColumn(name = "moduleId")
private Module module;
/**
* The parent module. Null, if root module.
*/
@ManyToOne(cascade = {CascadeType.ALL})
@JoinColumns( {
@JoinColumn(name = "parentAdtSessionModuleId", referencedColumnName = "adtSessionModuleId"),
@JoinColumn(name = "adtSessionId", referencedColumnName = "adtSessionId")})
// @Transient
private AdtSessionModule parentModule;
private String serial;
@ManyToOne
@JoinColumn(name = "hwTypeId")
private HWType hardwareType;
@ManyToOne
@JoinColumn(name = "manufacturerId")
private Manufacturer manufacturer;
@OneToMany(mappedBy="module", cascade = {CascadeType.ALL})
private Set<AdtResourceCheck> resourceChecks = new LinkedHashSet<AdtResourceCheck>();
//Not updatable nor insertable, since this is used as a discriminator
@Column(name="AdtSessionModuleTypeID", insertable=false, updatable=false)
private String type;
... methods follow ...
}
The method that generates the error is this (slightly edited for brevity):
Code:
private AdtSessionModule newSessionModule(AdtSession dbSession, AdtSessionModule module) {
AdtSessionModule adtSessionModule;
AdtSessionModuleAms ams = (AdtSessionModuleAms)module;
AdtSessionModuleAms amsModule = new AdtSessionModuleAms(dbSession, module.getAdtSessionModuleId());
amsModule.setFirmwareType(ams.getFirmwareType());
amsModule.setFirmwareVersion(ams.getFirmwareVersion());
amsModule.setHardwareVersion(ams.getHardwareVersion());
adtSessionModule = amsModule;
adtSessionModule.setManufacturer(module.getManufacturer());
adtSessionModule.setHardwareType(module.getHardwareType());
adtSessionModule.setSerial(module.getSerial());
adtSessionModule.setModule(module.getModule());
em.persist(adtSessionModule);
em.flush();
for (AdtSessionModule child : module.getChildren()) {
AdtSessionModule newModule = newSessionModule(dbSession, child);
adtSessionModule.addChild(newModule);
}
return adtSessionModule;
}
(I wish Hibernate could remember where in the code the various statements come from, but alas that's not easy with Java.)
I'm using hibernate that comes with JBoss 5.1.0 GA on a x86 Linux Ubuntu 8.10 system with an Oracle 10.0 database underneath. Despite the comment in the code, we use Java 1.6 (Sun java 1.6.0_10-b33)
I don't know any way I can control the ordering of the parameters, it's neither the code order nor the DB order, so I cannot work around it by putting the enum value last. Any ideas? Haven't found anything resembling this by searching around, either.
Thanks in advance,
-Lars