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
Related
I've generated a document using spring auto rest docs. This uses capital.scalable libraries combined with java docs and spring rest docs.
My issue is with the List of enums while describing the request fields.
Type column generates a value as Array[Object]. Also, the description column doesn't generate the must be one of statement with the enum values, as it does when only Enum is the field and not the list of enums.
public enum Discipline {
ECONOMICS("economics"),
SOCIOLOGYANTHROPOLOGY("sociologyanthropology");
private final String discipline;
Discipline(final String discipline) {
this.discipline = discipline;
}
public String getId() {
return discipline;
}
}
Above is the enum that I have. It uses tostring correctly to display in the description when the field is used only as enum. But if list of enums i.e.
List<Discipline>
is the field, then it doesn't describe properly as mentioned above.
Please let me know what should be done to generate the document more effectively?
You are right that lists of enums are not properly supported yet.
If you have a request/response like:
class SomeRequest {
public enum EnumTest {
ONE, TWO
}
/**
* List of enums
*/
private List<EnumTest> enumTestList;
}
it is documented as
with Spring Auto REST Docs at the moment.
It would be good if the type would be Array[String] and the description would list the elements of the enum, e.g. "Elements must be one of [...]".
Spring Auto REST Docs 1.0.11 fixes the type issue and thus Array[String] will be shown with this version.
I opened an issue to improve the documentation of lists of enums: https://github.com/ScaCap/spring-auto-restdocs/issues/194. Until this issue is resolved, one can manually add "Elements must be one of [...]" to the Javadoc of the list as a workaround.
I'm getting the following error when I run my tests:
org.dbunit.dataset.NoSuchColumnException: myTable.MYFIELD - (Non-uppercase input column: myfield) in ColumnNameToIndexes cache map. Note that the map's column names are NOT case sensitive.
at org.dbunit.dataset.AbstractTableMetaData.getColumnIndex(AbstractTableMetaData.java:117)
I set a breakpoint in org.dbunit.dataset.AbstractTableMetaData#getColumnIndex and discovered the following. In IntelliJ Idea the method looks like this:
public int getColumnIndex(String columnName) throws DataSetException
{
logger.debug("getColumnIndex(columnName={}) - start", columnName);
if(this._columnsToIndexes == null)
{
// lazily create the map
this._columnsToIndexes = createColumnIndexesMap(this.getColumns());
}
String columnNameUpperCase = columnName.toUpperCase();
Integer colIndex = (Integer) this._columnsToIndexes.get(columnNameUpperCase);
if(colIndex != null)
{
return colIndex.intValue();
}
else
{
throw new NoSuchColumnException(this.getTableName(), columnNameUpperCase,
" (Non-uppercase input column: "+columnName+") in ColumnNameToIndexes cache map. " +
"Note that the map's column names are NOT case sensitive.");
}
}
The value of this.getColumns() does not contain any Column with Column.columnName matching the parameter columnName. Therefore colIndex becomes null and the exception is thrown.
It looks like DBUnit is looking for the column index in the wrong table meta data.
How can I fix this?
Note: I inherited this code from someone else (didn't write it).
I'm sensitive to the fact that you can't really share code. That does make things a little difficult, but here's an answer I think is reasonable given the confines:
I was able to easily reproduce this exception using a minimal Spring Boot/DbUnit project cloned from GitHub. Perhaps my observations will amount to the hint you're looking for, or at least inspire a better answer.
Steps
Clone the project and install dependencies.
Run the HsqldbexampleApplicationTests.contextLoads() test. It passes.
Get into StaticResource.java, and change one of the #Column annotations.
For example, I changed:
#Column(name = "CONTENT")
private String content;
to:
#Column(name = "CONTENTZ")
private String content;
Run the test again and observe the exception
Alternatively, you can get into sampleData.xml and change the CONTENT attributes there (the attribute name), to produce the same exception.
Observations
The test gets its data from /META-INF/dbtest/sampleData.xml. Note the CONTENT attribute.
The resource has an #Column annotation whose name must match an attribute found in the sampleData.xml elements.
Since your trouble is also with running tests, it may be that your code and the .xml(?) that hydrates your test data store are simply out of sync with respect to a column name.
Further implication of an XML file?
My attempts to provoke this exception by changing queries and instance variable names were unsuccessful. Everything I tried made the compiler complain, so I ruled it out.
For example, I also checked out this repo, and tried to change a query and an instance variable, but was thwarted by the compiler at every step. Changing a query:
Changing an instance variable name:
Where to look
Anywhere in any java code where you have #Column with MYFIELD inside it. Remember, annotations can span several lines in a file.
Any xml files containing MYFIELD.
Assuming the code under test works fine, and your problems are confined to running tests, the mechanism that injects data into your test is the prime suspect. If this isn't an xml file, what is it?
It's not clear from you post how do you get the _columnsToIndexes
It looks like a piece of some reflection code that depends on your POJO.
In this case the problem migth be in Lazy initialization of the object. Lazy initialized objects are not just entity object but some kind of proxy and attemption of getting its properties through the reflection may cause this problem.
Probably you should try add some kind of unproxy method into you createColumnIndexesMap. Here is example:
public static <T> T initializeAndUnproxy(T entity) {
if (entity == null) {
throw new InternalServerException("Entity passed for initialization is null");
}
T unproxy = entity;
Hibernate.initialize(entity);
if (isProxy(entity)) {
unproxy = (T) ((HibernateProxy) entity).getHibernateLazyInitializer().getImplementation();
}
return unproxy;
}
public static <T> boolean isProxy(T entity) {
return entity instanceof HibernateProxy;
}
of course it depends on your ORM, here is example for Hibernate
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 am working on playframework and I have problem with scala forms when i apply the .get() methode to the form to create object i got all the object attributes are null.
here is my code:
import play.data.*;
import static play.data.Form.*;
public static Result save() {
Form<myobj> boundForm = cardForm.bindFromRequest();
if(boundForm.hasErrors()) {
flash("error", "Please correct the form below.");
return badRequest(page1.render(boundForm));
}
myobj temp= boundForm.get();
temp.save();
.
.
.
}
the problem is all the attributes in "temp" are null although when i add breakpoint in the intellij-idea and see the values inside the form i see that it has data
I had the same issue, the data binding stopped working at some point and all attributes was null.
The form.getData() gave back a map where all data was present, but the form's object was empty (all attribute null).
I suspected there is an error with the reflection, so deleted the target directory and compiled the classes again with the play framework. And now it works again.
I think it is a compatibility issue with the idea compiler versus play compiler, but I hadn't investigated the problem further.
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="/>