Im currently doing a side project to validate objects using java 8.
Currently I have this:
An interface that is essencially a rewrite of the java 8 predicate interface:
Then, I created the implementation of that same interface:
And then this class is the result of my validation
The concrete object validation can be found here:
public class ConcreteValidator implements EmployeeValidator {
#Override
public void validate(Employee employee) throws EmployeeException {
ValidatorUtil.notNullString.and(ValidatorUtil.notEmptyString)
.and(ValidatorUtil.stringBetween(1, 100)).test(employee.getFirstName())
.getFieldNameIfInvalid(" Please specify valid firstname ").orElse("");
ValidatorUtil.notNullString.and(ValidatorUtil.notEmptyString)
.and(ValidatorUtil.stringBetween(1, 100)).test(employee.getLastName())
.getFieldNameIfInvalid(" Please specify valid lastname ").orElse("");
ValidatorUtil.notNullString.and(ValidatorUtil.notEmptyString)
.and(ValidatorUtil.stringBetween(3, 100)).test(employee.getEmail())
.getFieldNameIfInvalid(" Please specify valid email ").orElse("");
ValidatorUtil.notNullInteger.and(ValidatorUtil.greaterThanZero)
.and(ValidatorUtil.integerBetween(18, 60)).test(employee.getAge())
.getFieldNameIfInvalid(" Please specify valid age ").orElse("");
}
}
This works fine but what I want to do now is to limit the user to use the notNull verification first, and only after that validation all the methods like notEmpty or greaterThanZero will be available.
I searched for fluent interfaces but don't know if it is the correct way to do it (want to do something like this: https://code-held.com/2019/04/29/robust-builder-pattern/)
To summarise, I want to force the developer to validate if the object is null first and all the other methods go next, something like the chaining of the Stream API in java-8.Here is my customValidations.
You can't, not with how you do your methods: <K> GenericValidation<K> from(Predicate<K> predicate).
By doing so, you tell the developer he can pass any Java expressions: you can't validate the content of the expression at runtime, unlike you want to play with bytecode - which you don't.
You need to enforce this using the compiler, for example:
GenericValidation<K> fromNonNull(Predicate<K> predicate) {
return from(val -> val != null && predicate.test(val));
}
Or using types as shown below:
validateThat(employee.getFirstName()) // return a StringValidator1
.isNotNull() // return a StringValidator2
.isNotEmpty()
.hasLengthBetween(1, 100)
;
StringValidator1 only have isNotNull() and return StringValidator2.
That's how you would enforce the isNotNull() check with the compiler: by returning another type providing more services than the default. Since StringValidator1 does not have isNotEmpty(), then the compiler would generate a compilation error by trying to call it.
You may read AssertJ code for how they do their fluent interface. There are of course other source code being fluent (and I think the most important part of "fluent", is that the compiler and IDE helps you in validating what you are doing).
Related
How can I distinguish in java graphQL if a parameter was explicitly set to null, or if it was not provided at all?
The use case that I try to achieve is the following: I have a mutation like this
updateUser(id:Int!, changes:UserChanges!)
#where UserChanges is defined as:
type UserChanges {
login:String
email:String
#etc
}
The idea here is that the user provides only the fields that he wants to change (like react setState for example).
So if email is ommited, I want to leave it unchanged.
But what if he/she wants to explicitly set email to null?
Is there any way figure this out from my resolver method and act accordingly?
(I use graphql-java-tools library)
I found the answer. In case somebody needs it:
An instance of graphql.schema.DataFetchingEnvironment is available to every resolver method.
This provides methods like getArguments(), hasArgument() etc.
Using those methods, we can find out if an argument was an explicit set to null, or if it was not provided at all.
Looks like deserialization from query/variables is handled by fasterxml Jackson, and that's proper place to deal with the issue, otherwise it becomes too complex: check every field? nested?
So: UserChanges.java should look like this:
class UserChanges {
// SHOULD NOT HAVE ALL ARGUMENT CONSTRUCTOR!
Optional<String> login;
Optional<String> email;
... getters & setters
}
in this case deserializer will use setters, ONLY FOR PROVIDED FIELDS!
And {"login":null} will become:
UserChanges.login = Optional.empty
UserChanges.email = null
I want to create a library (for own use to begin with but maybe for publishing later so I want to do it the proper way).
I'll use following (abstract) example to explain my question:
public void onSomeEvent(SomeEvent someEvent) {
String action = someEvent.getAction();
EventTypes eventTypes = getEventTypes(); //problem lies with this method
for (EventType eventType : eventTypes) {
if (eventType.getAction().equals(action)) {
eventType.onEvent(someEvent);
}
}
}
private EventTypes getEventTypes {
//User should have defined his own event-type-classes by extending EventType:
//What is the best way to let the user list/define these EventTypes
//so my API can access them (e.g. with this method)?
}
My question is as shown in the comment of the example:
What is the best way to let the user of my API define his own EventTypes for this EventReceiver of the API while meeting (in best case all of the) following criteria:
event-types are easy to define for users
not using reflection
user-types are not registered at runtime, but statically listed somewhere (without annotation-processor)
I don't know if these creteria can all be fulfilled (I guess not).
But if you neglect one or more of the criteria (the first one shouldn't be in any case), please explain to me why there is no better way of doing it (without writing my own annotation-processor).
I hope my question is clear.
If you think it isn't, please suggest me how to make it more precise.
If you think I'm missing out something or should make an entirely different approach, I'd be glad for your corrections.
Thank you in advance.
public List<? extends EventType> getEventTypes() {
...
}
Time to learn about Generics, my friend:
Lesson: Generics (Updated) (The Java Tutorials > Learning the Java Language)
I would define a new interface the user of your api can implement:
public interface EventType {
String getAction ();
[...]
}
And then implement your get method to access the event types to following way. You will then also need a list as a member of your class and a method to add new EventTypes:
private List<EventType> eventTypes = new List<>();
public void addEventType (EventType type) {
this.eventTypes.add(type);
}
public List<EventType> getEventTypes() {
return this.eventTypes;
}
The user of your API is than able to define new EventTypes by creating new classes implementing your interface.
Given a Google Cloud Endpoints project in Eclipse with the servlet-class annotated with #Api(name="helloworld"), the Endpoints framework generates a file named war/WEB-INF/helloworld-v1.api when the project compiles successfully. Sometimes this file is not generated even if there are no compilation errors though - only what I will call "GAE Endpoints code convention errors".
Example - working:
public class TestEntity {
public String Text;
public TestEntity(String text){
Text = text;
}
}
#ApiMethod
public TestEntity getTestEntity(){
return new TestEntity("Hello world");
}
Example - NOT working:
// The TestEntity-class is unchanged
#ApiMethod
public TestEntity getTestEntity(String input){
return new TestEntity("Hello world");
}
The problem with the latter example is that I take a String parameter as input without annotating it with #Named. I know that in this example, but there might be other cases where this is not so obvious.
Is there anywhere where I can read some sort of error log on why the .api file is not generated?
Although I am a fan of code by convention, it really takes the programming efficiency a step back if I cannot get feedback on what I do wrong. Eclipse provides compiler error feedback. The Google Cloud Endpoints Framework should provide Code-By-Convention-Rule-Breaking feedback.
There isn't currently good logging or error messaging when code generation fails, though it's one of the (if not most) requested features. In the interim, here's a list of the common failure cases:
The return type is invalid. Return types must be objects conforming to JavaBean conventions, and types like Object, String, and Integer are not allowed.
One or more argument types are invalid. Methods may accept at most one object in the POST body, and this object should also conform to JavaBean conventions. Methods may accept zero or more arguments via the query string (using the #Named annotation) and these must be scalar types (e.g. String, Integer).
An API, method, or parameter has an invalid name. APIs, methods, and parameters should be named to match the following regular expression: [a-z]+[A-Za-z0-9]*. Convention also suggests using lowerCamelCase for naming (though alllowercase is allowed).
I have a scenario where I need to authorize user based on combination of his permission and input parameter passed.
this is the current scenario
public void bookTicket(String bookingType)
{
if (bookingType == "AIR"){
bookAirTicket();
}else{
bookBusTicket();
}
}
#PreAuthorize("hasRole('BOOK_AIR')")
private void bookAirTicket(){
}
#PreAuthorize("hasRole('BOOK_BUS')")
private void bookBusTicket(){
}
Can we have some thing like
#PreAuthorize(("hasRole('BOOK_AIR')" AND bookinType='AIR') OR ("hasRole('BOOK_BUS')" AND bookinType='BUS'))
public void bookTicket(String bookingType)
{
if (bookingType == "AIR"){
bookAirTicket();
}else{
bookBusTicket();
}
}
Basically I need authorization based in input parameters
Thanks
Yes, you can. Parameters can be accessed as Spring EL variables. In fact the reference manual gives several examples which use method parameters. The class needs to be compiled with debug symbols present (which is usually the case).
Note that the annotation value is a single expressions string:
"(hasRole('BOOK_AIR') and #bookinType == 'AIR') or (hasRole('BOOK_BUS') and #bookinType='BUS')"
In practice, using complicated expressions is rather error-prone. You could also use a simpler expression, something like
"#accessChecker.check('book', #bookinType)"
Where accessChecker is a bean in your application context with a "check" method which returns true or false depending on whether the supplied operation information is allowed (you can check the current user's roles by accessing the security context yourself - you'll find that discussed elsewhere on SO).
You could also look into writing your own AccessDecisionManager or AccessDecisionVoter and plugin the functionality there, but that requires more internal knowledge.
How can I change what a method is doing in Java ?
I mean, I am trying to use annotations to make the following code
#Anno1(Argument = "Option1")
public class TestClass
{
#Anno2
public void test()
{
}
}
Into
public class TestClass
{
private static StaticReference z;
public void test()
{
z.invokeToAll();
}
}
This is a very simplified example of what I am trying to do. Anno1 will have many possible combinations, but this is not my problem so far. My problem is how to add code to method test()
I am looking for a more generic solution if possible. Eg. A way to add every kind of code in the method (not just a way to .invokeToAll())
So far I am using import javax.annotation.processing.*; and I have the following code, but I don't know how to go on from there
private void processMethodAnnotations(RoundEnvironment env)
{
for (Element e : env.getElementsAnnotatedWith(Anno2.class))
{
//If it is a valid annotation over a method
if (e.getKind() == ElementKind.METHOD)
{
//What to do here :S
}else
{
processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING,"Not a method!", e);
}
}
}
I have found something about Java Reflection but I have not found any source to help me with what I am doing.
Obviously I extends AbstractProcessor in my code
I have found this tutorial (http://www.zdnetasia.com/writing-and-processing-custom-annotations-part-3-39362483.htm) But this concerns creating a new class, not just changing a method. and the javax.lang.model.elements do not provide any way of editing that element (which in my case represents a Method).
I hope my question is clear and inline with the rules. If not please comment and I will clarify. Thanks.
Annotation processing is the wrong way to go for you, from Wikipedia:
When Java source code is compiled,
annotations can be processed by
compiler plug-ins called annotation
processors. Processors can produce
informational messages or create
additional Java source files or
resources, which in turn may be
compiled and processed, but annotation
processors cannot modify the annotated
code itself.
People suggested to you the right way - AOP. Specifically, you can use AspectJ. "Quick result" way is (if you use Eclipse):
Install AJDT (AspectJ Development Tools)
Create an AspectJ project and add there your classes and annotations
Create Aspect:
public aspect Processor {
private StaticReference z;
pointcut generic()
// intercept execution of method named test, annotated with #Anno1
// from any class type, annotated with #Anno2
: execution(#Anno2 * (#Anno1 *).test())
// method takes no arguments
&& args ();
// here you have written what you want the method to actually do
void around () : generic() {
z.invokeToAll();
}
}
now you can execute a test and you will see that it works ;) AJDT compiles code for you automatically, so do not need any manual work to do, hope that's what you called "magic" ;)
UPDATE:
if your code in the test() method depends on the Anno1 annotation value, then inside aspect you can get class annotation for which it is executed this way:
void around () : generic() {
Annotation[] classAnnotations = thisJoinPoint.getThis().getClass().getAnnotations();
String ArgumentValue = null;
for ( Annotation annotation : classAnnotations ) {
if ( annotation instanceof Anno1 ) {
ArgumentValue = ((Anno1) annotation).Argument();
break;
}
}
if ( ArgumentValue != null && ArgumentValue.equals("Option1")) {
z.invokeToAll();
}
}
where thisJoinPoint is a special reference variable.
UPDATE2:
if you want to add System.out.println( this ) in your aspect, you need to write there System.out.println( thisJoinPoint.getThis() ), just tested and it works. thisJoinPoint.getThis() returns you "this" but not exactly; in fact this is Object variable and if you want to get any propery you need either to cast or to use reflection. And thisJoinPoint.getThis() does not provide access to private properties.
Well, now seems that your question is answered, but if I missed anything, or you get additional question/problems with this way - feel free to ask ;)
It's perfectly possible to do what you ask, although there is a caveat: relying on private compiler APIs. Sounds scary, but it isn't really (compiler implementations tend to be stable).
There's a paper that explains the procedure: The Hacker's Guide to Javac.
Notably, this is used by Project Lombok to provide automatic getter/setter generation (amongst other things). The following article explains how it does it, basically re-iterating what is said the aforementioned paper.
Well, you might see if the following boilerplate code will be useful:
public void magic(Object bean, String[] args) throws Exception {
for (Method method : bean.getClass().getDeclaredMethods()) {
if (method.isAnnotationPresent(Anno2.class)) {
// Invoke the original method
method.invoke(bean, args);
// Invoke your 'z' method
StaticReference.invokeAll();
}
}
}
As an alternative your might employ aspect oriented programming, for instance you have the AspectJ project.
I'm not sure at all if it is even possible to change the source or byte code via annotations. From what your describing it looks as if aspect oriented programming could provide a solution to your problem.
Your annotations are pretty similiar to the pointcut concept (they mark a location where code needs to be inserted) and the inserted code is close the advice concept.
Another approach would be parsing the java source file into an abstract syntax tree, modify this AST and serialize to a java compiler input.
If your class extends a suitable interface, you could wrap it in a DynamicProxy, which delegates all calls to the original methods, except the call to test.