Can queries reference transient fields?

I have a query that works until I add a String field named base64Image. Eclipse is giving me the following error (line wraps added for readability) when I try to log into the application via a browser:

org.hibernate.HibernateException: Errors in named queries: 
Product.findAllForJsp failed because of: org.hibernate.QueryException: 
could not resolve property: base64Image of: com.bookstore.entity.Product 
[SELECT NEW com.bookstore.transferobjects.ProductListJSP(
p.id, p.catalogCode, p.category.name, p.title, p.subtitle, p.base64Image, 
p.priceRange, p.lastUpdateTime) 
FROM com.bookstore.entity.Product p ]

This field, base64Image is marked @Transient.

My goal was to include this field on a transfer class for a JSP page. It holds an image of the product for display. I managed a workaround by swapping in a reference to the byte[] field that is in the underlying MySQL db, instead of the @Transient field, and converting the data in the transfer class constructor.

Is the issue that named queries cannot reference transient fields of a class? I am new to Hibernate queries, and I don’t want to deduce an incorrect conclusion!

My project uses: JavaSE with Hibernate 5.4.27 and JPA 2.2.

Below is the “Product” class with some irrelevant constructors and queries weeded out. The query “Product.findAllForJsp” is in it’s failing form. If the reference to “base64Image” is removed, or replaced by “image”, the application allows me to log in without throwing exceptions.


@Entity
@NamedQueries({
	@NamedQuery(name = "Product.findAll",	query = "SELECT p FROM Product p " 
			+ "ORDER BY p.title"),
	@NamedQuery(name = "Product.findAllForJsp",	
			query = "SELECT NEW com.bookstore.transferobjects.ProductListJSP("
					+ "p.id, p.catalogCode, p.category.name, p.title, "
					+ "p.subtitle, p.base64Image, p.price, p.lastUpdateTime) "
					+ "FROM Product p "))
})
@Table(name = "product", catalog = "xxxxxxxxxxxdb", uniqueConstraints = @UniqueConstraint(columnNames = "title"))
public class Product implements java.io.Serializable {

	private static final long serialVersionUID = 1L;
	private Integer id;
	private String title;
	private String subtitle;
	private String catalogCode;
	private String description;
	private byte[] image;
	private String base64Image;
	private String priceRange;
	private Date creationDate;
	private Date lastUpdate;
	private Category category;
	private Set<ProductDetail> productDetails = new HashSet<ProductDetail>(0);
	private Set<OrderDetail> orderDetails = new HashSet<OrderDetail>(0);

	public Product() {}
	
	public Product(Integer id) {
		super();
		this.id = id; 
	}

	public Product(String title, String subtitle, 
			String catalogCode, String description, 
			byte[] image, String priceRange, Date creationDate,  
			Date lastUpdate, Category category) {
		
		this.title = title;
		this.subtitle = subtitle;
		this.catalogCode = catalogCode;
		this.description = description;
		this.image = image;
		this.priceRange = priceRange;
		this.creationDate = creationDate;
		this.lastUpdate = lastUpdate;
		this.category = category;
	}

	@Id
	@GeneratedValue(strategy = IDENTITY)

	@Column(name = "id", unique = true, nullable = false)
	public Integer getId() {
		return this.id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	@Column(name = "title", unique = true, nullable = false, length = 128)
	public String getTitle() {
		return this.title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	@Column(name = "subtitle", nullable = false, length = 64)
	public String getSubtitle() {
		return this.subtitle;
	}

	public void setSubtitle(String subtitle) {
		this.subtitle = subtitle;
	}
	
	@Column(name = "catalog_code", unique = true, nullable = false, length = 25)
	public String getCatalogCode() {
		return this.catalogCode;
	}
	
	public void setCatalogCode(String catalogCode) {
		this.catalogCode = catalogCode;
	}

	@Column(name = "description", nullable = false, length = 16777215)
	public String getDescription() {
		return this.description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	@Column(name = "image", nullable = false)
	public byte[] getImage() {
		return this.image;
	}

	public void setImage(byte[] imageBytes) {
		this.image = imageBytes;
	}

	@Column(name = "price_range", nullable = false, length = 30)
	public String getPriceRange() {
		return this.priceRange;
	}

	public void setPriceRange(String priceRange) {
		this.priceRange = priceRange;
	}

	@Temporal(TemporalType.DATE)
	@Column(name = "creation_date", nullable = false, length = 10)
	public Date getCreationDate() {
		return this.creationDate;
	}

	public void setCreationDate(Date creationDate) {
		this.creationDate = creationDate;
	}
	
	@Temporal(TemporalType.TIMESTAMP)
	@Column(name = "last_update", nullable = false, length = 19)
	public Date getLastUpdate() {
		return this.lastUpdate;
	}

	public void setLastUpdate(Date lastUpdate) {
		this.lastUpdate = lastUpdate;
	}

	@ManyToOne(fetch = FetchType.EAGER)
	@JoinColumn(name = "category_fkey", nullable = false)
	public Category getCategory() {
		return this.category;
	}

	public void setCategory(Category category) {
		this.category = category;
	}
	
	@OneToMany(fetch = FetchType.LAZY, mappedBy = "product")
	public Set<ProductDetail> getProductDetails() {
		return this.productDetails;
	}

	public void setProductDetails(Set<ProductDetail> productDetails) {
		this.productDetails = productDetails;
	}
	
	@OneToMany(fetch = FetchType.LAZY, mappedBy = "product")
	public Set<OrderDetail> getOrderDetails() {
		return this.orderDetails;
	}

	public void setOrderDetails(Set<OrderDetail> orderDetails) {
		this.orderDetails = orderDetails;
	}
	
	@Transient
	public String getBase64Image() {
		this.base64Image = Base64.getEncoder().encodeToString(image) ;
		return this.base64Image;
	}
	
	@Transient
	public void setBase64Image(String base64Image) {
		this.base64Image = base64Image;
	}
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Product other = (Product) obj;
		if (id == null) {
			if (other.id != null)
				return false;
		} else if (!id.equals(other.id))
			return false;
		return true;
	}
	
}

Transient fields/properties are ignored i.e. invisible to Hibernate, so you can’t refer to those in JPQL/HQL or JPA Criteria. This is usually used to transfer some transient state without affecting the persistence logic. You will have to pass image i.e. the byte[] which is a persistent field to the constructor instead and then do the Bas64 encoding to a String in that constructor.

1 Like

Thank you for confirming!