I'm getting started with Spring Roo. So far so good, it seems like a decent Java option for CRUD based applications.
I've created a basic web app using one of the SpringRoo tutorials online as a base.
I've set up the basic scaffolding, and it appears that objects that have a one-to-many relationship are listed as such in the application:
List all Exam Modules
Difficulty Category Exam Id
Easy Software Design 2013-02-28 15:01:29.0 2013-02-28 15:01:29.0 Test Software Exam
Exam Id is a reference to an Exam entity as follows:
import org.springframework.roo.addon.dbre.RooDbManaged;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.jpa.activerecord.RooJpaActiveRecord;
import org.springframework.roo.addon.tostring.RooToString;
#RooJavaBean
#RooJpaActiveRecord(versionField = "", table = "exam")
#RooDbManaged(automaticallyDelete = true)
public class Exam {
#Override
public String toString() {
return id + ": " + desc;
}
}
Before, toString was configured using #RooToString
This has not been reflected in the web app, so perhaps the string that is displayed there does not invoke the toString method.
My code in the jspx is as follows:
<table:column id="c_com_mypackage_examino_domain_ExamModule_examId" property="examId" z="iz7M0ohWIJEbf7nEYqPLkvKKtcE="/>
Any idea on how to get this exam entity to print out a nice, family friendly string?
Look in the ApplicationConversionServiceFactoryBean.java (or .aj). There will be a method along the lines of
public Converter<Exam, String> getExamToStringConverter()
or
public Converter<ExamPK, String> getExamToStringConverter()
Change that so it only includes the fields you want to see.
Alternatively, you can just add a bean style method in Exam.java that returns the string you want and call it as a property. This assumes you've created a method named getMyExamId() that returns the string you want. Notice you'll need to change z to 'user-managed'
<table:column id="c_com_mypackage_examino_domain_ExamModule_examId" property="myExamId" z="user-managed="/>
Related
I am trying to find the effective way to automate the API contract validation. Validations should cover
Field Mandatory or Optional
Field length
Field Type
Structure
Values not allowed
We are using Java with RESTAssured. For few APIs, in the past I have developed individual tests for each field & each validation (like below).
Ex: Test Employee Name is Mandatory (Submit an API request with empty Employee Name)
Test Employee Name is String (Submit an API request with number in Employee Name)
Test Employee name field length (Submit an API request with empty Employee Name more than allowed length)
This approach works but I guess there might be effective ways. Looking for suggestions.
I think using parameterized test will solve a part of your problem. The main idea is:
Provide a csv file (or any kinds), each line can contain data test and corresponding error message.
One line = one test.
Example:
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
public class DemoTest {
#ParameterizedTest
#CsvSource({
",name cannot be blank",
"lucas,name cannot less than 6 chars"
})
void test1(String name, String errorMsg){
System.out.printf("name=%s, errorMsg=%s", name, errorMsg);
}
}
The example goes with Junit5, you can do the same with TestNG #DataProvider
What you are referring to is JSON schema , you can create a schema for your api response mentioning which all fields are mandatory and then use it with postman or restassured .
You can generate schema using :
https://www.jsonschema.net/login
I am trying to generate a CSV mapping for the fields of a class in Java in an automatic way since I need to use it several times.
I have the following method for trying to get the field names: (where CSV header is something like "DB_NAME|FIELD_NAME|ADDITIONAL_F1|ADDITIONAL_F2")
package util;
import java.lang.reflect.Field;
public class CsvAttributesMappingGenerator {
public static String generateCsvAttributesMapping(Class<?> model) {
StringBuilder csvBuilder = new StringBuilder();
Field[] fieldList = model.getDeclaredFields();
for (Field field : fieldList) {
//field.setAccessible(true);
csvBuilder.append(field.getName().replaceAll("(.)(\\p{Upper})", "$1_$2").toUpperCase());
csvBuilder.append("|");
csvBuilder.append(field.getName());
csvBuilder.append("||\n");
}
return formatOutput(csvBuilder.toString());
}
private static String formatOutput(String classText) {
String delimiter = "\n******************************\n";
return String.format("%s%s%s", delimiter, classText, delimiter);
}
}
and a test call like:
import objects.User;
import org.junit.Test;
import util.CsvAttributesMappingGenerator;
public class CsvAttributesMappingGeneratorTest {
#Test
public void testGenerationWithObject() {
System.out.println(CsvAttributesMappingGenerator.generateCsvAttributesMapping(User.class));
}
}
The object to be parsed has the following structure:
package objects;
public class User {
private String userName;
private String userEmail;
private int userAge;
private String otherDetails;
// getters, setters and all args constuctor here
}
The output should have multiple rows like FIELD_NAME|fieldName|| where the camel cased item should be collected from the given class. I attempted to use Java Reflection API as I have seen on several examples but I get a strange String output instead. (not the serialized #randomCharsLikeName). Tried toString() and other dirty tricks but nothing worked.
Can someone tip me up a little with this? Or at least tell me if it is possible to do what I tried?
Thanks in advance!
EDIT: the current code prototype presented in the question works in an isolated environment (separate new project) and displays the expected output. It does not work though integrated within the whole application I am trying to integrate it into. I will keep researching and let you know the root cause (in the real app I am using also lombok for the classes (
#AllArgsConstructor, #NoArgsConstructor, #Data, #ToString
), but I do not honestly think that this might be an issue while using Reflection)
I found the issue in the meanwhile. While I was play-prototyping the generator, I used:
csvBuilder.append(field.getClass().getName().replaceAll("(.)(\\p{Upper})", "$1_$2").toUpperCase());
which produced outputs like JAVA.LANG.REFLECT._FIELD|java.lang.reflect.Field||
Since I simply forgot that I actually improved it to use actual class object as a parameter to the function. Before asking the question I made some Sonar fixes to the code and did not notice that I fixed a WARN to remove the .getClass() method invocation since I already pass in a class (I thought it would not make a difference since it is just a warning). Moral tip of the day - NEVER EVER ignore warnings.
So the code snippets presented in the question work fine now in an isolated dummy project and also integrated within a more complex project, using the fixed line:
csvBuilder.append(field.getName().replaceAll("(.)(\\p{Upper})", "$1_$2").toUpperCase());
Also as someone suggested in the comments, the field.setAccessible(true); can be removed since it is useless for the purpose of the method.
I've created a simple Grails app connecting to a table in an Oracle 12 database which is supposed to provide a CRUD for data there. So I have a simple model class like this:
package moduleprototype
class ConfigTest {
int configid
String name
String type
String value
String description
int status
static constraints = {
version false
id column: 'CONFIGID', name:'configid', type: 'integer'
}
}
And the controller:
package moduleprototype
class ConfigTestController {
static scaffold = ConfigTest
}
But when I navigate to the controller in my browser, while all the data from the config_test table is displayed properly, it's all plain text in a table, not clickable links for every value which would allow you to change them (which they should be according to the official guide). Why is that?
The scaffolding is on in the controller so it should theoretically work, and from what I remember from the tutorial app, that was enough for it to automatically allow in-browser modification interface so I'm guessing the reason here is that I'm using an external database instead of the built-in one? How can I fix this so that all the values are again clickable, modifiable and deletable?
EDIT: So to better illustrate my problem, here's an example of scaffolding from the tutorial app where in every row, every value is a link to the /show/ page where a given value can be modified or deleted (which is what I'm trying to achieve):
While in my case, everything (weirdly, apart from the first column, which is my id) is just plain text. The values in the configid column, though, are links, but all just pointing to itself (i.e. /ConfigTest/index).
The scaffolding mechanism needs to find a field named id to work.
Just change your domain class to
package moduleprototype
class ConfigTest {
int id //int configid
String name
String type
String value
String description
int status
static mapping /*constraints*/ = {
version false
id column: 'CONFIGID', name:'id' /*name:'configid'*/, type: 'integer'
}
}
At least that fixed that error for me with a small test with grails 3.3
I am creating Client API in Java using :+ Apache Jena FrameWork+ Hydra(for Hypermedia driven) + my private vocab similar to Markus Lanther Event-API Vocab instead of schema.org(for Ontology/Vocabulary part)
Section 1 :
After looking this Markus Lanther EventDemo repo and hydra-java.I found that they are creating classes for each hydra:Class that can break client in future .For example :
A Person class (Person.java)
public class Person
{
String name;
};
But in future requirement name is also a class eg:
public class Name
{
String firstName;
String LastName;
};
So to fulfill this requirement I have to update Person class like this:
public class Person
{
Name name;
};
Question 1:
Is my understanding correct or not of this Section? If yes then what is the way to deal with this part ?
Section 2:
To avoid above problem I created a GenericResource class(GenericResource.java)
public class GenericResource
{
private Model model;
public void addProperty(String propertyName,Object propertyValue)
{
propertyName = "myvocab:"+propertyName;
//Because he will pass propertyName only eg: "name" and I will map it to "myvocab:name"
//Some logic to add propertyName and propertyValue to model
}
public GenericResource retriveProperty(String propertyName)
{
propertyName = "myvocab:"+propertyName;
//Some logic to query and retrieve propertyName data from this Object add it to new GenericResource Object and return
}
public GenericResouce performAction(String actionName,String postData)
{
//Some logic to make http call give response in return
}
}
But again I stuck in lots of problem :
Problem 1: It is not necessary that every propertyName is mapped to myvocab:propertyName. Some may be mapped to some other vocab eg: hydra:propertyName, schema:propertyName, rdfs:propertyName, newVocab:propertyName, etc.
Problem 2: How to validate whether this propertyName belongs to this class ?
Suggestion: Put type field/variable in GenericResource class.And then check supportedProperty in vocab corresponding to that class.To more clarity assume above Person class which is also defined in vocab and having supportedProperty : [name,age,etc] .So my GenericResource have type "Person" and at time of addProperty or some other operation , I will query through vocab for that property is in supportedProperty list or in supportedOperation list in case of performAction().
Is it correct way ? Any other suggestion will be most welcomed?
Question 1: Is my understanding correct or not of this Section? If yes
then what is the way to deal with this part ?
Yes, that seems to be correct. Just because hydra-java decided to creates classes doesn't mean you have to do the same in your implementation though. I would rather write a mapper and annotate an internal class that can then stay stable (you need to update the mapping instead). Your GenericResource approach also looks good btw.
Problem 1: It is not necessary that every propertyName is mapped to
myvocab:propertyName. Some may be mapped to some other vocab eg:
hydra:propertyName, schema:propertyName, rdfs:propertyName,
newVocab:propertyName, etc.
Why don't you store and access the properties with full URLs, i.e., including the vocab? You can of course implement some convenience methods to simplify the work with your vocab.
Problem 2: How to validate whether this propertyName belongs to this
class
Suggestion: Put type field/variable in GenericResource class
JSON-LD's #type in node objects (not in #value objects) corresponds to rdf:type. So simply add it as every other property.
And then check supportedProperty in vocab corresponding to that class.
Please keep in mind that supportedProperty only tells you which properties are known to be supported. It doesn't tell you which aren't. In other words, it is valid to have properties other than the ones listed as supportedProperty on an object/resource.
Ad Q1:
For the flexibility you want, the client has to be prepared for semantic and structural changes.
In HTML that is possible. The server can change the structure of an html form in the way outlined by you, by having a firstName and lastName field rather than just a name field. The client does not break, rather it adjusts its UI, following the new semantics. The trick is that the UI is generated, not fixed.
A client which tries to unmarshal the incoming message into a fixed representation, such as a Java bean, is out of luck, and I do not think there is any solution how you could deserialize into a Java bean and survive a change like yours.
If you do not try to deserialize, but stick to reading and processing the incoming message into a more flexible representation, then you can achieve the kind of evolvability you're after. The client must be able to handle the flexible representation accordingly. It could generate UIs rather than binding data to fixed markup, which means, it makes no assumptions about the semantics and structure of the data. If the client absolutely has to know what a data element means, then the server cannot change the related semantics, it can only add new items with the new semantics while keeping the old ones around.
If there were a way how a server could hand out a new structure with a code-on-demand adapter for existing clients, then the server would gain a lot of evolvability. But I am not aware of any such solutions yet.
Ad Q2:
If your goal is to read an incoming json-ld response into a Jena Model on the client side, please see https://jena.apache.org/documentation/io/rdf-input.html
Model model = ModelFactory.createDefaultModel() ;
String base = null;
model.read(inputStream, base, "JSON-LD");
Thus your client will not break in the sense that it cannot read the incoming response. I think that is what your GenericResource achieves, too. But you could use Jena directly on the client side. Basically, you would avoid unmarshalling into a fixed type.
I have configured my spring Application as below:
// Spring MVC controller
#Controller
HelloController {
#ResponseBody
Student getData() {
return student from database;
}
}
public Class Student {
#Trim(device = "mob", trim=10)
#Trim(device = "desktop", trim=100)
String name ;
Address address;
}
public class Address {
#Trim(device = "mob", trim=10 )
#Trim(device = "desktop", trim=100 )
String addressInfo
}
Requirements:
After the Controller returns the Student, do modification of Student object and all complex attributes inside it based on the Annotation,
for example if the request was from mobile trim the student name to 10 and so on.
Approaches I can think of:
Recursively iterate on fields with annotation and modify fields.
Iteration on class fields every time can be hectic, as the class is complex and can nest up to n levels.
Create a List of Annotated fields at server start up and when then iterate on this list and apply changes to the target object.
I am currently struggling with both approachs. So would like to know whether there exists some prebuilt solutions or design patterns to handle such scenarios.
I actually coded the Reflection based approach and created a library some time back.
It uses reflection to identify annotation on fields and then takes the appropriate action based on the input device.
Here is the link for library
https://github.com/santoshjoshi/Adaptive-Device-Data-Filtering