Compiletime validation of enum parameters - java

There is a constructor with three parameters of type enum:
public SomeClass(EnumType1 enum1,EnumType2 enum2, EnumType3 enum3)
{...}
The three parameters of type enum are not allowd to be combined with all possible values:
Example:
EnumType1.VALUE_ONE, EnumType2.VALUE_SIX, EnumType3.VALUE_TWENTY is a valid combination.
But the following combination is not valid:
EnumType1.VALUE_TWO, EnumType2.VALUE_SIX, EnumType3.VALUE_FIFTEEN
Each of the EnumTypes knows with which values it is allowed to be combined:
EnumType1 and the two others implement a isAllowedWith() method to check that as follows:
public enum EnumType1 {
VALUE_ONE,VALUE_TWO,...;
public boolean isAllowedWith(final EnumType2 type) {
switch (this) {
case VALUE_ONE:
return type.equals(Type.VALUE_THREE);
case VALUE_TWO:
return true;
case VALUE_THREE:
return type.equals(Type.VALUE_EIGHT);
...
}
}
I need to run that check at compile time because it is of extreme importance in my project that the combinations are ALWAYS correct at runtime.
I wonder if there is a possibility to run that check with user defined annotations?
Every idea is appreciated :)

The posts above don't bring a solution for compile-time check, here's mine:
Why not use concept of nested Enum.
You would have EnumType1 containing its own values + a nested EnumType2 and this one a nested EnumType3.
You could organize the whole with your useful combination.
You could end up with 3 classes (EnumType1,2 and 3) and each one of each concerned value containing the others with the allowed associated values.
And your call would look like that (with assuming you want EnumType1.VALUE_ONE associated with EnumType2.VALUE_FIFTEEN) :
EnumType1.VALUE_ONE.VALUE_FIFTEEN //second value corresponding to EnumType2
Thus, you could have also: EnumType3.VALUE_SIX.VALUE_ONE (where SIX is known by type3 and ONE by type1).
Your call would be change to something like:
public SomeClass(EnumType1 enumType)
=> sample:
SomeClass(EnumType1.VALUE_ONE.VALUE_SIX.VALUE_TWENTY) //being a valid combination as said
To better clarify it, check at this post: Using nested enum types in Java

So the simplest way to do this is to 1) Define the documentation to explain valid combinations and
2) add the checks in the constructor
If a constructor throws an Exception than that is the responsibility of the invoker. Basically you would do something like this:
public MyClass(enum foo, enum bar, enum baz)
{
if(!validateCombination(foo,bar,baz))
{
throw new IllegalStateException("Contract violated");
}
}
private boolean validateCombination(enum foo, enum bar, enum baz)
{
//validation logic
}
Now this part is absolutely critical. Mark the class a final, it is possible that a partially constructed object can be recovered and abused to break your application. With a class marked as final a malicious program cannot extend the partially constructed object and wreak havoc.

One alternative idea is to write some automated tests to catch this, and hook them into your build process as a compulsory step before packaging/deploying your app.
If you think about what you're trying to catch here, it's code which is legal but wrong. While you could catch that during the compilation phase, this is exactly what tests are meant for.
This would fit your requirement of not being able to build any code with an illegal combination, because the build would still fail. And arguably it would be easier for other developers to understand than writing your own annotation processor...

The only way I know is to work with annotations.
Here is what I do I mean.
Now your constructor accepts 3 parameters:
public SomeClass(EnumType1 enum1,EnumType2 enum2, EnumType3 enum3){}
so you are calling it as following:
SomeClass obj = new SomeClass(EnumTupe1.VALUE1, EnumTupe2.VALUE2, EnumTupe1.VALUE3)
Change the constructor to be private. Create public constructor that accept 1 parameter of any type you want. It may be just a fake parameter.
public SomeClass(Placeholder p)
Now you have to require to call this constructor while each argument is annotated with special annotation. Let's call it TypeAnnotation:
SomeClass obj = new SomeClass(TypeAnnotation(
type1=EnumType1.VALUE1,
type2=EnumTupe2.VALUE2,
type3=EnumTupe1.VALUE3)
p3);
The call is more verbose but this is what we have to pay for compile time validation.
Now, how to define the annotation?
#Documented
#Retention({RetentionPolicy.RUNTIME, RetentionPolicy.SOURCE})
#Target(PARAMETER)
#interface TypeAnnotation {
EnumType1 type1();
EnumType2 type3();
EnumType3 type3();
}
Please pay attention that target is PARAMETER and retention values are RUNTIME and SOURCE.
RUNTIME allows reading this annotation at runtime, while SOURCE allows creating annotation processor that can validate the parameters at runtime.
Now the public constructor will call the 3-parameters private construcor:
public SomeClass(Placeholder p) {
this(readAnnotation(EnumType1.class), readAnnotation(EnumType2.class), readAnnotation(EnumType3.class), )
}
I am not implementing readAnnotation() here: it should be static method that takes stack trace, goes 3 elements back (to caller of the public costructor) and parses annotation TypeAnnotation.
Now is the most interesting part. You have to implement annotation processor.
Take a look here for instructions and here for an example of annotation processor.
You will have to add usage of this annotation processor to your build script and (optionally) to your IDE. In this case you will get real compilation error when your compatibility rules are violated.
I believe that this solution looks too complicated but if you really need this you can do this. It may take a day or so. Good luck.

Well, I am not aware of a compile time check but I do not think it is possible because how can the compiler know which value will be passed to the constructor (In case the value of your enum variable is calculated in runtime (e.g. by an If clause) ?
This can only be validated on runtime by using a validator method as you implemented for the enum types.
Example :
If in your code you have something like this :
EnumType1 enumVal;
if (<some condition>) {
enumVal = EnumType2.VALUE_SIX;
} else {
enumVal = EnumType2.VALUE_ONE;
}
There is no way the compiler can know which of the values will be assigned to enumVal so it won't be able to verify what is passed to the constructor until the if block is evaluated (which can be done only in runtime)

Related

parametrize #Interface annotation in Java

I have an #interface annotation type like this -
public #interface someAnnotation {
String someVar() default "var_value";
}
I want to parametrize someVar on a Junit5 test similar to this
#ParametrizedTest
#ValueSource(strings = {"val1","val2"})
#someAnnotation(someVar = ??)
void theTestMethod(String s){
//test something
}
I want the value of s (that is provided by valueSource) to be loaded to someVar. Obviously something like this won't work -
#someAnnotation(someVar = s)
I have also tried using Test Extension by implementing BeforeEachCallback to get ExtensionContext using which someVar can be accessed but I have found no way to get ValueSource values or method parameters values from ExtensionContext. Is there any way to achieve this?
The Java Language Specification section on annotations says, in brief, that element values must not be null and may only be:
constant expressions
class literals
enum constants
arrays whose elements are one of the above
Therefore, what you're asking for isn't permitted by the language.
The only way I know of to achieve this kind of variability over an annotation's values in a test would be to have the test generate source code and compile it on the fly (or, equivalently, generate bytecode directly).
Stylistically, I would argue that unless your #ValueSource has more than ~50 elements, it's simpler and clearer to the reader to just write out each case like:
#Test
#someAnnotation(someVar = "val1")
void theTestMethodVal1(){
theTestMethodHelper("val1");
}
#Test
#someAnnotation(someVar = "val2")
void theTestMethodVal2(){
theTestMethodHelper("val2");
}
void theTestMethodHelper(String s){
//test something
}
All that having been said, it's not clear to me what the goal of tests like this might be.
As is clear from the hard-coding of "val1" and "val2" in the bodies of the above methods, it's much clearer and more concise to simply inline a needed value in the body of a method, rather than jumping through the reflection hoops that would be necessary to read that same value dynamically from an annotation on the method.

Accessing field in Java based on condition

I have to write a utility method that can get the particular variable value from an Object,
on evaluating some conditions.
Below are the requirements.
if "name" is coming as type call "getName" to get the Value.
If "subtype" is coming as type call "getSubType" to get the Subtype Value.
Current Solution:
public Object getFieldValue(String type, IDTO dto){
Method method = dto.getClass().getMethod("get"+createMethodName(type));
Object returnedObject = method.invoke(dto, null);
return returnedObject;
}
However, the operations are quite heavy and it is giving performance issues. Is there any alternative that can be chosen or any better way to do this.
Other points:
Interface IDTO has all the getter setters declared only. No fields declared in that.
If you need performance I would suggest to use code generation for the utility method doing the needed access to IDTO objects. Usually this would be integrated into the build. Your generated method could use a well performing switch statement for every 'type', for example:
/**
* Utility for generic access to IDTO object properties.
* GENERATED code, do not change! See template ....
*/
public Object getFieldValue(String type, IDTO dto){
switch (type) {
case "name" : return dto.getName();
case "subtype" : return dto.getSubtype();
...
}
// ERROR handling
throw new RuntimeException("unknown property");
}
To implement your generator code you could use reflection in the same way as you're code above already does.
For a more extensive usage of that approach I would suggest to introduce a simple template engine, see for example https://freemarker.apache.org

How to type cast via reflection when the class is package private

First, this is similar to this question but there was never a satisfactory answer. Second: I know, I know, reflection is bad, but it is the only option I have.
Question: Given a class
package a.pkg.outside.my.code;
class ClassIWant { // Package private class
public ClassIWant instance() {...}
}
I want to call instance(), obtaining an instance of ClassIWant, and return a ClassIWant (not an Object).
I can successfully call instance via reflection and get my hands on an Object:
public class MyClass {
/* type var T will always take value ClassIWant. I can currently get
* get this to type check by using Class.cast and changing return
* type to T, but this doesn't solve my problem.
*/
public <T> ClassIWant callInstance() { // Here T is ClassIWant
Class<T> clazz = Class.forName("a.pkg.outside.my.code.ClassIWant");
Object result = _use reflection_;
return (ClassIWant) result; // Fails at runtime
}
}
The issue is that I don't have access to ClassIWant to cast, and the best I've been able to do is call clazz.cast(result). This returns type T, which doesn't quite do what I want.
It's not even clear to me that this is possible, but my program has been type checking and getting illegal access errors at runtime. This tells me that all the bits and pieces fit together on the type level, and that methods are all pointing to the right place.
Note: It may be possible to change my use case to not need an explicit ClassIWant, but this would probably be a fair amount of work (i.e., lots and lots of calls to reflection). For brevity I haven't included the use case---I'll treat this as a second question if need be.
Edit: Updated in response to Andy Turner's comment (thanks for the catch): in more detail, I'm not explicitly using T here, but I have access to it and I want to make that explicit

How can we access methods generated by ByteBuddy in compilation time?

I wrote this example:
E someCreateMethod(Class<E> clazz) {
Class<? extends E> dynamicType = new ByteBuddy()
.subclass(clazz)
.name("NewEntity")
.method(named("getNumber"))
.intercept(FixedValue.value(100))
.defineField("stringVal", String.class, Visibility.PRIVATE)
.defineMethod("getStringVal", String.class, Visibility.PUBLIC)
.intercept(FieldAccessor.ofBeanProperty())
.make()
.load(clazz.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
return dynamicType.newInstance();
}
And I would like to use it to get the redefined number atributte:
Integer num = someCreateMethod(EntityExample.class).getNumber(); //(1)
Or to get the newly defined stringVal attribute:
String sVal = someCreateMethod(EntityExample.class).getStringVal(); //(2)
My problem is that (1) works pretty fine, while (2) doesn't. I get the following error:
Error:(40, 67) java: cannot find symbol
symbol: method getStringVal()
Also, is it possible to do something like this with a dynamic generated class:
NewEntity newEntity = someCreateMethod(EntityExample.class);
Integer num = newEntity.getNumber();
String sVal = newEntity.getStringVal();
?
EDIT: I appreciate your help, this example was my first attempt on using ByteBuddy library. I figured that defineMethod actually defines an implementation of an interface method, not just add a random method to the class. So I decided to explain here what exactly I'm trying to accomplish.
For every Date attribute in a class E, I want to add two more fields (and theirs respectives getters and setters), let's say (atribute name)InitialDate and (atribute name)FinalDate, so that I can use intervals functinality for every date in E.
I was wondering if I could use code-generation to add those methods without having to create subclasses for every E.
PS: E can't be changed, it belongs to a legacy module.
PS2: I don't know how many date attributes there would be in each entity E, but the new attibutes and methods would be created using conventions (for example __FisrtDay , __LastDay), as shown below:
NewA a = eb.create(A.class);
a.getDeadLine(); //inherited
a.getDeadLineFirstDay(); //added
a.getDeadLineLastDay(); //added
NewA b = eb.create(B.class);
b.getBirthday(); //inherited
b.getBirthdayFirstDay(); //added
b.getBirthdayLastDay(); //added
b.getAnniversary(); //inherited
b.getAnniversaryFirstDay(); //added
b.getAnniversaryLastDay(); //added
PS3: Is what I'm trying to accomplish even possible with ByteBuddy or at all? Is there another way?
PS4: Should my EDIT have been a new question?
You need E to be a superclass/ or interface which includes the methods you are trying to call -- you will not be able to resolve subtyped methods which do not exist on E.
This is not a ByteBuddy issue, this is an issue of your class design -- you should design & group the functionality you intend to generate into abstractable parts, so it can be exposed via types which are meaningful at compile time.
For example, we could use a supertype 'ValueProvider' and then use ByteBuddy to define an IntConstantProvider.
public interface ValueProvider<T> {
public T getValue();
}
Class<? extends ValueProvider<Integer>> dynamicType = new ByteBuddy()
.subclass(clazz)
.name("ConstantIntProvider")
.method(named("getValue"))
.intercept(FixedValue.value(100))
// etc.
Your prototype had 3 separate functionalities (if we consider unreference private fields to be the stub of some intended behavior) with no obvious abstraction to encompass them. This could be better designed as 3 simple atomic behaviors, for which the abstractions would be obvious.
You could use reflection to find arbitrary methods on a arbitrary dynamically-defined class, but this is not really meaningful from a coding or design POV (how does your code know which methods to call? if it does know, why not use a type to express that?) nor is it very performant.
FOLLOWING EDIT TO QUESTION -- Java Bean properties work by reflection, so the example of finding "related properties" (such as First/ Last Date) from known properties is not unreasonable.
However it could be considered to use a DateInterval( FirstDate, LastDate) class so that only one supplementary property is needed per- base property.
As Thomas points out, Byte Buddy generates classes at runtime such that your compiler cannot validate their existance during compile time.
What you can do is to apply your code generation at build time. If your EntityExample.class exists in a specific module, you can enhance this module with the Byte Buddy Maven or Gradle plugin and then, after enhancement, allow your compiler to validate their existance.
What you can also do would be to define interfaces like
interface StringVal {
String getStringVal();
}
which you can ask Byte Buddy to implement in your subclass which allows your compiler to validate the method's existance if you represent your subclass as this interface.
Other than that, your compiler is doing exactly what it is supposed to do: telling you that you are calling a method that does not exist (at that time).

How to override instance/concrete class's method runtime? (e.g. reflection, cglib)

What I wanna do is a method that can
generate instance of Class X (a class variable passed in arg) and
override some of it's method
More specifically, the parent class X I want to override contains
Contains no default constructor (e.g. all constructors with args)
Constructors calling non-private method within the same class
Originally I thought it's quite simple to use reflection or something similar,
Then I found there's limitation on implementing my requirement.
For refection: Can only override "interface" via java.lang.reflect.Proxy
http://download.oracle.com/javase/1.3/docs/guide/reflection/proxy.html
for cglib: it cannot create instance of no default constructor and constructor calling non-private member methods
http://insufficientinformation.blogspot.com/2007/12/spring-dynamic-proxies-vs-cglib-proxies.html
I think this is achievable, since Mockito can do all kinds of method injection runtime.
Please anyone give some advise, Thanks.
The pseudo-code I image is like this:
createAndOverride(Class X) {
X newObj = X.newInstance(args) {
#override
methodOfX(args2) {
...
}
}
return newObj;
}
Original problem scenario
I was intended to test a Class which has several methods calling X1.get(), X2.get(), X3.get()
In some test case, I need to make Xn.get() to return something I can control for test (e.g. null)
Due to below constraint:
But due to mock tool restriction to JMock 1.0 (I have no control :( ), so I cannot just simply mock Xn.get() to returns "someSpecifiedObjects"
Xn has no null constructors and constructors calling non-private member
My workaround is self made Xn Class and pass them to test case to let Cn.get() to be expected
code example:
ClassToTest.SomeMethod(new X1() {
#override
get() {
return someSpecifiedObjects;
}
});
And this kind of thing is spread-ed over the Test Case.
Therefore, In order to reduce duplicate code, I would like to build a method to generate Xn instance with specified overrided method for test. e.g.
X1 x1 = createAndOverride(X1);
Then, the problem of this post comes
are you looking for something like javassist? You can instrument code and inject your methods at runtime. I personally try to avoid byte code manipulation as much as possible. Can you not have these overrides in your code base rather than doing on the fly? May be something like wrappers?
So what I think you need is a similar functionality to C#'s Reflection.Emit:
Using Reflection.Emit to create a class implementing an interface
Java Equivalent of Reflection.Emit
Dynamically Create Java Classes With JavaClassCreator
While I haven't done this myself, I think you should be able to use reflection/emission and dynamic type creation in order to achieve what you're looking for. However, I would still like to mention that if you're trying to test "functionality" that's not int he code path of the function you're testing, then you probably shouldn't be testing it at all. For example:
SomeObjectInterface get()
{
if(_someObjectStateIsSet)
{
// Return a concrete implementation A
return new ConcreteImplA();
}
else
{
// Return a concrete implementation B
return new ConcreteImplB();
}
}
In this case get has no code path that would return null, so you shouldn't need to test for null. I'm not sure if I understood your question 100% correctly, especially why you're testing for null, but consider the above advice and see what works for you.

Categories