JPA/Hibernate - PropertyAccessException


#1

Hi, ich sitze gerade an einer Aufgabe für die Uni und kann daher das Datenmodell nicht ändern. Das Datenmodell sieht so aus:

Das consistsOf der TaskForce macht Probleme. Ich bekomme folgende Exception: javax.persistence.PersistenceException: org.hibernate.PropertyAccessException: could not get a field value by reflection getter of dst.ass1.jpa.model.impl.TaskForce.id.

Meine Klasse sieht so aus:

@Entity
public class TaskForce implements ITaskForce {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @Column(unique = true)
    private String name;
    private Date lastMeeting;
    private Date nextMeeting;

    @ManyToMany(mappedBy = "partOf", targetEntity = TaskForce.class)
    private List<ITaskForce> composedOf = new LinkedList<ITaskForce>();

    @ManyToMany(targetEntity = TaskForce.class)
    @JoinTable(name="composed_of")
    private List<ITaskForce> partOf = new LinkedList<ITaskForce>();

    @OneToMany(targetEntity = TaskWorker.class)
    private List<ITaskWorker> taskWorkers = new LinkedList<ITaskWorker>();
    @ManyToOne(targetEntity = Expert.class)
    private IExpert expert;
    @ManyToOne(targetEntity = WorkPlatform.class)
    private IWorkPlatform workPlatform;


    @Override
    public Long getId() {
        return this.id;
    }

    @Override
    public void setId(Long id) {
        this.id = id;
    }
    // restlichen getter/setter
}

Einer der Testfälle der das auslöst sieht so aus:

	@SuppressWarnings("unchecked")
	@Test
	public void testNamedQueryFindUsersWithActiveMembership2() {
		EntityTransaction tx = em.getTransaction();
		try {
			tx.begin();
			Query query = em
					.createNamedQuery(Constants.Q_USERSWITHACTIVEMEMBERSHIP);
			query.setParameter("name", "foobar");
			query.setParameter("minNr", 2L);

			List<IUser> result = (List<IUser>) query.getResultList();

			assertNotNull(result);
			assertEquals(0, result.size());

		} catch (Exception e) {

			fail(ExceptionUtils.getMessage(e));

		} finally {
			tx.rollback();
		}
	}

Hat einer eine Ahnung was es hier hat?


#2

Im Mapping keine Fehler zu erkennen. Kannst Du mal den Querystring Constants.Q_USERSWITHACTIVEMEMBERSHIP posten?


#3

Hi, der Name wird dich nicht weiter interessieren. Aber ich kann gerne das NamedQuery (samt dazugehöriger Entity) posten:

@NamedQueries({
        @NamedQuery(name = Constants.Q_USERSWITHACTIVEMEMBERSHIP, query =
                " SELECT mem.user "
                        + "FROM Membership mem "
                        + "WHERE mem.workPlatform.name = :name AND "
                        + "(SELECT COUNT(tsk) FROM Task tsk "
                        + " JOIN tsk.taskProcessing tskproc "
                        + " JOIN tskproc.taskWorkers tskwrkr"
                        + " JOIN tskwrkr.taskForce tskfrc "
                        + " JOIN tskfrc.workPlatform wrkplat "
                        + " WHERE wrkplat.name = :name"
                        + " AND tsk.user = mem.user) >= :minNr"),
        @NamedQuery(name = Constants.Q_MOSTACTIVEUSER, query =
                " SELECT user " +
                        " FROM User user " +
                        " WHERE user.tasks.size = (SELECT MAX(tmpU.tasks.size) FROM User tmpU) " +
                        " AND user.tasks.size > 0")
})
@Entity
public class User extends Person implements IUser {
    private String username;
    @Column(columnDefinition = "BINARY(16)")
    @Index(name = "IDX_PASSWORD")
    private byte[] password;
    @Column(unique = true)
    private String accountNo;
    @Column(unique = true)
    private String bankCode;
    @OneToMany(targetEntity = Task.class)
    private List<ITask> tasks = new LinkedList<ITask>();
    @OneToMany(targetEntity = Membership.class)
    private List<IMembership> memberships = new LinkedList<IMembership>();

    // getter/setter
}

Es ist generell so, dass die TaskForce-Klasse an mehreren Stellen gebraucht wird. Der Test oben ist nur exemplarisch. Es schlagen 39 Tests mit dieser Exception fehl. Hier noch die TaskProcessing Entity:

@Entity
public class TaskProcessing implements ITaskProcessing {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private Date start;
    private Date end;
    @Enumerated(EnumType.STRING)
    private TaskStatus status;
    @ManyToMany(targetEntity = TaskWorker.class)
    @JoinTable(name="PROCESSING_TASKWORKER",
            joinColumns={@JoinColumn(name="TASKPROCESSINGS_ID", referencedColumnName="ID")},
            inverseJoinColumns={@JoinColumn(name="TASKWORKERS_ID", referencedColumnName="ID")})
    private List<ITaskWorker> taskWorkers;
    @OneToOne(targetEntity = Task.class)
    private ITask task;
// getter/setter
}

Und der TaskWorker:

@Entity
@EntityListeners({ WorkerListener.class })
public class TaskWorker implements ITaskWorker {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @Column(unique = true)
    @Size(min=5, max = 25)
    private String name;
    @WorkUnitCapacity(min=4, max=8)
    private Integer workUnitCapacity;
    @Size(min=12)
    @Pattern(regexp = "[A-Z]{3}-[A-Z]@[0-9]+")
    private String location;
    @Past
    private Date joinedDate;
    @Past
    private Date lastTraining;
    private List<ITaskProcessing> processings = new LinkedList<ITaskProcessing>();
    private ITaskForce taskForce;
// getter/setter

WorkUnitCapacity ist nur eine custom Validation. Kannst du ignorieren.