Issue 42: Properties of primitive type cannot be used
Status:  New
Owner: ----
Reported by tomwhois...@gmail.com, Jul 6, 2012
Compile and run:

@Entity
public class Prisoner {
	
	@Id
	private int number;
	
	public int getNumber() {
		return number;
	}
	
}

public class Rover {
	
	public static void main(String[] args) {
		Prisoner p = alias(Prisoner.class, "p");
		SubQuery<Prisoner> q = select(p).from(Prisoner.class).as(p).where(eq(p.getNumber(), 6));
		System.out.println(q);
	}
	
}

I would expect to see:

select p from Prisoner as p where p.number = 6

Instead, i see:

Exception in thread "main" java.lang.UnsupportedOperationException: Can't create object of type int. This may happen if you forgot to annotate a persistent class with @Entity
	at com.google.code.liquidform.internal.FrameworkObjectFactory.makeNew(FrameworkObjectFactory.java:96)
	at com.google.code.liquidform.internal.FrameworkObjectFactory.makeNew(FrameworkObjectFactory.java:51)
	at com.google.code.liquidform.internal.PropertyAccessRecordingInvocationHandler.intercept(PropertyAccessRecordingInvocationHandler.java:68)
	at Prisoner$$EnhancerByCGLIB$$15e8fdb7.getNumber(<generated>)
	at Rover.main(Rover.java:13)

If i change the return type of getNumber to Integer, the expected output is produced.

This occurs with the 1.0.1 release, and with the code at the head of the current trunk (r149).

The immediate problem is that FrameworkObjectFactory.makeNew does not know about int, or any other primitive type. Thus, AIUI, aliases cannot be constructed for any property of primitive type, and so no references can be made to such a property at all.

This problem is not simple to fix. makeNew could make instances of Integer when an alias for an int property is needed. However, this alias cannot be remembered correctly. It can be put into the AliasFactory.bindings map, but when it is returned through the proxy via the PropertyAccessRecordingInvocationHandler, it will be unboxed to a primitive int, at which point the object's identity is lost. It will then be re-boxed in order to be passed to an alias-consuming method (such as eq in the example above), creating an object with an entirely new identity, which will fail to evoke any memory in AliasFactory.safeAbout, and so will be treated as a literal.

By way of illustration, if i amend makeNew to treat int the same as Integer, i end up with the query:

select p from Prisoner as p where 42 = 6

Which is amusing, but alas useless.

Other libraries which use remembering proxies, such as Mockito, solve this problem by making assumptions about method call order, namely that memories will be recalled immediately after being created. This leads to magical and occasionally incredibly confusing behaviour. In LiquidForm, it would impose restrictions on the use of the DSL which would be incompatible with the advice given in the user guide about factoring queries for readability.

I have failed to think of a way to solve this problem in a convenient and reliable way. I wish you better luck!