Skip to content
This repository has been archived by the owner on Sep 10, 2021. It is now read-only.

activation rules for constraints not working for programming by contract #7

Closed
spik3r opened this issue May 17, 2017 · 6 comments
Closed

Comments

@spik3r
Copy link

spik3r commented May 17, 2017

Activation rules don't seem to work when using Programming by contract with AspectJ.
As per the documentation this works when using a Validator:

public class BusinessObject {
    private String fieldA;
    
    @NotNull(when = "javascript:_this.fieldA != null")
    private String fieldB;
    
    public BusinessObject(){}
    
    public BusinessObject(String fieldA, String fieldB) {
        this.fieldA = fieldA;
        this.fieldB = fieldB;
    }
    
    public String getFieldA() {
        return this.fieldA;
    }
    public void setFieldB(String fieldB) {
        this.fieldB = fieldB;
    }
}

But applying the same concept using Guarded does not.

@Guarded
public class Pojo {
    private String fieldA;
    private String fieldB;
    
    public Pojo(
            String fieldA,
            @NotNull(when = "javascript:_this.fieldA != null") String fieldB) {
        
        this.fieldA = fieldA;
        this.fieldB = fieldB;
    }
    
    public String getFieldA() {
        return this.fieldA;
    }
}
@sebthom
Copy link
Owner

sebthom commented May 17, 2017

Your example does not work because _this is a reference to the object you are about to create. The when expression is checked before the value of the argument fieldA is assigned to the field this.fieldA.

Activation of a parameter constraint depending on another parameter's value is currently not possible.

You can try using a @PostValidateThis constraint, e.g.

@Guarded
public class Pojo {
    private String fieldA;

    @NotNull(when = "javascript:_this.fieldA != null")
    private String fieldB;
    
    @PostValidateThis
    public Pojo(String fieldA, String fieldB) {
        this.fieldA = fieldA;
        this.fieldB = fieldB;
    }
    
    public String getFieldA() {
        return this.fieldA;
    }
}

@spik3r
Copy link
Author

spik3r commented May 18, 2017

Hi Sebastian,
thanks for your quick response, unfortunately your code snipped doesn't work for me and throws a java.lang.StackOverflowError, unless I remove the getter. Unfortunately if I do that the JavaScript can't find the variable anymore

Is there some limitation to using @PostValidateThis?
It seems to only work when there is no when expression.
I think there may be a bug when using @PostValidateThis with when and either a public variable or getter since this exact combination always throws a java.lang.StackOverflowError even in a another example (slightly modified version of the example from 4.4.4 of the OVal documentation)

@Guarded
public class MethodPostValidation {
    
    private boolean someVariable = true;

    @MaxLength(value = 10)
//    @MaxLength(value = 10, when = "javascript:_this.someVariable == true") // Uncomment this to get StackOverflowError
    private String name = "12345";
    
    MethodPostValidation(){}
    
    MethodPostValidation(boolean someVariable) {
        this.someVariable = someVariable;
    }
    
    @PostValidateThis
    public void appendToName(String appendix) {
        name += appendix;
    }
    
    public boolean getSomeVariable() {
        return this.someVariable;
    }
}

Basic example tests:

public class MethodPostValidationTest {
    @Test(expected = ConstraintsViolatedException.class)
    public void getFieldTooLongThrowsException() throws Exception {
        MethodPostValidation methodPostValidation = new MethodPostValidation();
        methodPostValidation.appendToName("asdfghjkl");
        
    }
    
    @Test
    public void getFieldSomeVariableFalseDoesNotValidateNoException() throws Exception {
        MethodPostValidation methodPostValidation = new MethodPostValidation(false);
        methodPostValidation.appendToName("asdfghjkl");
    }
}

@sebthom
Copy link
Owner

sebthom commented May 19, 2017

I cannot really reproduce the issue. I extended the respective test case and it seems to work fine, see c676ef2

There are two things you need to be aware of:

  1. The JavaScript Engine Rhino cannot directly access private fields. E.g. something like "javascript:_this.myPrivateField != null && _this.myPrivateField.length > 10" will always return false, no matter the value of the private field. Rhino apparently does not raise an exception if it cannot access the private field. I would recommend you to use groovy instead of javascript for constraint activation.
  2. For most scripting runtimes (including JavaScript) the statement _this.someVariable will result in the invocation of the _this.getSomeVariable() getter and not in a direct access of a private field with the same name.

@spik3r
Copy link
Author

spik3r commented May 20, 2017

Hi Sebastian,
thanks again.

I noticed that javascript couldn't see private variables for some reason.
I've got it working using @PostValidateThis as long as I add @Guarded(checkInvariants = false) otherwise I get a StackOverflowError from the getters.

@Guarded(checkInvariants = false)// removing this results in StackOverflowError
public class User {
    private final String firstName;
    private final String lastName;
    @NotNull(when = "groovy:_this.lastName != null")
    private final Integer age;

    @PostValidateThis
    public User(String firstName, String lastName, Integer age) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public Integer getAge() {
        return age;
    }
}

@sebthom
Copy link
Owner

sebthom commented May 22, 2017

I added a fix for the StackOverflowError. Can you please give the latest snapshot a try: http://oval.sourceforge.net/mvn-repo/snapshot/net/sf/oval/oval/1.88-SNAPSHOT/

@spik3r
Copy link
Author

spik3r commented May 22, 2017

I've tested the latest snapshot and can confirm I no longer get the StackOverflowError.
Thanks again for the quick fix.

@spik3r spik3r closed this as completed May 22, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants