I have created two domain classes like below:
Component:
class Component {
String name;
Integer orderOfComponent;
Boolean limitedAccess;
Date dateCreated;
String alignment;
String type;
static belongsTo = [subpage: Subpage]
static constraints = {
name nullable: false, blank: false;
orderOfComponent nullable:false, blank: false;
limitedAccess nullable: true, blank: true;
alignment nullable: true, blank: true, inList: ["left", "right", "center", ""];
type nullable: false, blank: false, inList: ["text", "image", "document", "html"];
subpage nullable: false, blank: false;
}
}
Text:
class Text extends Component {
String text;
String color;
String additionalStyle;
String textType;
String link;
static constraints = {
text nullable: true, blank: true;
color nullable: true, blank: true;
additionalStyle nullable: true, blank: true;
textType nullable: true, blank: true, inList: ["p", "h1", "h2", "h3", ""];
link nullable: true, blank: true;
}
}
Everything is fine when I create instance of Component class:
new Component(name: "component" + i, orderOfComponent: i, limitedAccess: new Boolean(false), alignment: "right", type: "text", subpage: Subpage.get(1)).save(flush:true, failOnError:true);
But I get Error when I try to do similar for Text class:
new Text(name: "componentText",
orderOfComponent: 0,
limitedAccess: new Boolean(false),
alignment: "right",
type: "text",
subpage: Subpage.get(1),
text: "asdasdasdasd",
color: "#0F0C0A",
additionalStyle: "",
textType: "p",
link: "http://google.pl").save(flush:true, failOnError:true);
Error:
Error 2014-01-28 02:27:10,453 [localhost-startStop-1] ERROR context.GrailsContextLoader - Error initializing the application: Validation Error(s) occurred during save():
- Field error in object 'adminpanel.component.Text' on field 'type': rejected value [null]; (...)
And also very similar "Message".
Does someone know why I cannot create an instance of the Text class or how to use constructor of inheritor class properly? Thanks in advance.
Related
I'm struggling in returning only selected fields in my TypeORM find request.
Assuming the following request
const data = await AppDataSource.manager.find(User, {
select: {
id: true,
hash: true,
firstname: true,
lastname: false,
},
take: 10, // Just here to shrink dataset
});
The script works pretty well excepted that it return every field of my model, with default value initialized.
[
User {
prefix: 'usr',
hash: 'usr_835b0ad2-XXXXXX',
email: undefined,
accountValidated: false,
role: 'free',
myKeyOne: true,
myKeyTwo: false,
gender: 'unspecified',
lastConnexion: 2023-01-19T10:11:02.733Z,
pendingDeletion: false,
deletionDate: undefined,
firstname: 'Clément',
lastname: undefined,
password: undefined,
facebookId: undefined,
googleId: undefined,
id: 158
},
...
]
Of course, it's not usable as it, because I have extensive relations, and thus the payload would be extremely heavy.
Are you aware of a method / a way to remove all unnecessary fields ?
i.e. I'm expecting
[
User {
id: 124,
hash: 'urs_XXXX',
firstname: 'Clément',
},
...
]
In older versions of typeorm I think you need to select with an array of strings, try:
select: ["id", "hash", "firstname"],
See this older version of the docs: https://github.com/typeorm/typeorm/blob/bc60dd559ba42af083ddea17f01205c78c83c7e0/docs/find-options.md
After hours of researches I've finally found out why it behaved like this.
TypeORM relies on class definitions and typescript so...
if you have typescript default values OR if you have rewrite your constructor, all the "default" properties are injected.
Assuming a User model
❌ You should not do
#Entity({ name: 'users' })
class User {
#Column()
firstname?: string;
#Column({ nullable: true })
lastname?: string;
#Column({ unique: true, nullable: false })
email!: string;
#Column({ name: 'account_validated', nullable: false})
accountValidated?: boolean = false
//Your other fields...
}
✅ You should do
#Entity({ name: 'users' })
class User {
#Column()
firstname?: string;
#Column({ nullable: true })
lastname?: string;
#Column({ unique: true, nullable: false })
email!: string;
// Use default argument of the decorator
#Column({ name: 'account_validated', nullable: false, default: false})
accountValidated?: boolean
//Your other fields...
}
And if you need in some way to init a default, then create a public static method which return the Entity instead of using the constructor.
#Entity({ name: 'users' })
class User {
//...fields
public static init(...params): User {
let _user = new User()
//...populate your object
return _user
}
}
According to the documentation:
http://docs.grails.org/latest/ref/Constraints/Usage.html
a display: constraint should control whether a property is displayed in views.
Example:
static constraints = {
username(nullable: false, blank: false, unique: true)
password(nullable: false, blank: false, password: true)
firstname(nullable: true, blank: true)
surname(nullable: true, blank: true)
mail(nullable: true, blank: true)
lastLogged(nullable: true, blank: true, display: false)
}
Looking at the code above, last logged column should not be present in the view, however the column is still there.
Environment Information: grails 5
Can someone give me a hint why the constraint is not working as it should?
Thanks in advance.
I wanted to use encryption to encrypt user data in Grails 2.5.4 application. I followed the instructions on downloading configuring the 1.3.1 version of plugin.
Updated my Java Security JCE files in JDK 1.8 (both in JDK jre and standalone JRE directories).
I found some posts here which were similar and applied the fixes like the
lower case i in configFIlePath.
def configFilePath = System.getenv('ENCRYPTION_CONFIG_LOCATION') ?: "file:${userHome}"
configFilePath += "/.jasypt.groovy"
grails.config.locations = [configFilePath]
I also tried with configuration inside the Config.groovy
jasypt {
algorithm = "PBEWITHSHA256AND256BITAES-CBC-BC"
providerName = "BC"
password = "test"
keyObtentionIterations = 1000
}
My domain object is defined as follows:
package com.xyz
import java.util.Date;
import com.bloomhealthco.jasypt.*
class UserProfile {
String firstName
String lastName
Date dateOfBirth
// USATT membership information
long usattID
Date expirationDate
// contact information
String email
String phone
String streetAddress
String city
String state
String zipCode
String country
String gender
String club
// no reference to SecUser
static belongsTo = SecUser
static hasMany = [tournamentEntries: TournamentEntry]
static constraints = {
firstName blank: false, maxSize: 384, type: GormEncryptedStringType
lastName blank: false, maxSize: 384, type: GormEncryptedStringType
dateOfBirth blank: false
gender blank: false, type: GormEncryptedStringType
email blank: false, maxSize: 384, type: GormEncryptedStringType
phone blank: false, maxSize: 384, type: GormEncryptedStringType
streetAddress blank: false, maxSize: 384, type: GormEncryptedStringType
city blank: false, maxSize: 384, type: GormEncryptedStringType
state blank: false, type: GormEncryptedStringType
zipCode blank: false, type: GormEncryptedStringType
country blank: false, maxSize: 384, type: GormEncryptedStringType
expirationDate nullable: true
}
}
No matter what I try the data in my Domain object is not getting encrypted as far as I can tell by viewing it via Grails dbconsole application.
I turned on debug logging but don't see any logs from jasypt.
I suspect the main issue is the use of type within your constraints and not within mapping as the documentation explains.
I'd recommend you change you constraints to look like this:
static constraints = {
firstName blank: false, maxSize: 384
lastName blank: false, maxSize: 384
dateOfBirth blank: false
gender blank: false
email blank: false, maxSize: 384
phone blank: false, maxSize: 384
streetAddress blank: false, maxSize: 384
city blank: false, maxSize: 384
state blank: false
zipCode blank: false
country blank: false, maxSize: 384
expirationDate nullable: true
}
And add mappings just after the constraints like this:
static mapping = {
firstName type: GormEncryptedStringType
lastName type: GormEncryptedStringType
gender blank: false, type: GormEncryptedStringType
email type: GormEncryptedStringType
phone type: GormEncryptedStringType
streetAddress type: GormEncryptedStringType
city type: GormEncryptedStringType
state type: GormEncryptedStringType
zipCode blank: false, type: GormEncryptedStringType
country type: GormEncryptedStringType
}
I am developing Asp.Net MVC5 Application with jqGrid.
i have two models University and Religion.
public class University
{
public int UniversityID { get; set; }
public string UniversityName { get; set; }
}
public class Religion
{
public int ReligionID { get; set; }
public string ReligionName { get; set; }
}
I have a model called Student in which the above two classes are nested.
public class Student
{
public int StudentId { get; set; }
public string StudentName { get; set; }
public DateTime DOB { get; set; }
public string Gender { get; set; }
public University University { get; set; }
public Religion Religion { get; set; }
}
I filled the jqGrid with list of students.
//jqGrid binding through ajax Post
var jsonUnivList = $.parseJSON('#Html.Raw(Json.Encode(Model.Universities))'); //IEnumerable list of Universities
var jsonReligionList = $.parseJSON('#Html.Raw(Json.Encode(Model.Religions))'); // IEnumerable list of Religion
$("#list2").jqGrid({
url: '/Student/StudentGridData',
datatype: "json",
colNames: ['Student Id', 'Student Name', 'Gender', 'DOB', 'University', 'Religion'],
colModel: [
{ name: 'StudentId', index: 'StudentId', width: 70, hidden: true },
{ name: 'StudentName', index: 'StudentName', width: 130, sortable: true, editable: true, formoptions: { label: 'Name *' }, editoptions: { class: "validate[required]", "data-errormessage-value-missing": "*Name Required", "onblur": "$(this).validationEngine('validate');" } },
{
name: 'Gender', index: 'Gender', width: 80, align: "right", sortable: true, editable: true, edittype: 'select',
editoptions:
{
value: { '': '--select gender--', 'M': 'MALE', 'F': 'FEMALE' }
}
},
{ name: 'DOB', index: 'DOB', formatter: 'date', formatoptions: { srcformat: 'd/m/Y', newformat: 'ShortDate' }, width: 150, align: "right", sortable: true, editable: true, formoptions: { label: 'DOB *' }, editoptions: { class: "validate[required]", "data-errormessage-value-missing": "*DOB Required", "onblur": "$(this).validationEngine('validate');" } },
{
name: 'University.UniversityName', index: 'University.UniversityName', width: 150, align: "right", sortable: true, editable: true, edittype: 'select', formoptions: { label: 'Name *' },
editoptions:
{
dataUrl: '',
buildSelect: function (data) {
var s = '<select name="UniversityID" >';
if (jsonUnivList && jsonUnivList.length) {
for (var i = 0, l = jsonUnivList.length; i < l ; i++) {
s += '<option value="' + jsonUnivList[i].UniversityID + '">' + jsonUnivList[i].UniversityName + '</option>';
}
}
return s + "</select>";
},
class: "validate[required]", "data-errormessage-value-missing": "*University Required", "onblur": "$(this).validationEngine('validate');"
}
},
{
name: 'Religion.ReligionName', index: 'Religion.ReligionName', width: 150, align: "right", sortable: true, editable: true, edittype: 'select', formoptions: { label: 'Name *' },
editoptions:
{
dataUrl: '',
buildSelect: function (data) {
var s = '<select name= "ReligionID">';
if (jsonReligionList && jsonReligionList.length) {
for (var i = 0, l = jsonReligionList.length; i < l ; i++) {
s += '<option value="' + jsonReligionList[i].ReligionID + '">' + jsonReligionList[i].ReligionName + '</option>';
}
}
return s + "</select>";
},
class: "validate[required]", "data-errormessage-value-missing": "*Religion Required", "onblur": "$(this).validationEngine('validate');"
}
}
],
rowNum: 10,
rowList: [10, 20, 30],
pager: '#pager2',
sortname: 'StudentId',
mtype: 'POST',
viewrecords: true,
sortorder: "desc",
caption: "Student List",
editurl: '/Student/AddEditStudent'
});
$("#list2").jqGrid('navGrid', '#pager2',
{
edit: true, add: true, del: true, search: true,
searchtext: "Search", addtext: "Add", edittext: "Edit", deltext: "Delete"
}
);
After i clicked on Add option of jqGrid and filled the details (Uiversity and Religion are dropdowns - nested models of student). The filled data will be passed to Controller.
[HttpPost]
public void AddEditStudent(Student StudentModel)
{
}
But when i check the data received in controller,
i recieve the following data:
StudentName
DOB
Gender
But these are coming null:
University
Religion
Note: This problem arise only in the case of jqGrid,
If i submit from page(same textboxes and dropdown) then everything is ok.
This is how I would have modeled my Student Object :
public class Student
{
public int StudentId { get; set; }
public string StudentName { get; set; }
public DateTime DOB { get; set; }
public string Gender { get; set; }
public int UniversityID { get; set; }
public int ReligionID { get; set; }
}
In JQ Grid I bind options in a slightly different manner than yours. This is how I would bind options to the University column :
editoptions : "1:Stanford;2:Harvard;3:Yale"
Now when you save, the Id of the selected option will be mapped to the corresponding property of Student object
(I am assuming you are using saveRow function of jqGrid to submit data.)
Finally i figured it out
{
name: 'University.UniversityID', index: 'University.UniversityName', jsonmap: "University.UniversityName", width: 150, align: "right", sortable: true, editable: true, edittype: 'select', formoptions: { label: 'University *', name: "University.UniversityID" },
editoptions:
{
value: valUnivList, // List of university as keyvalue pair
class: "validate[required]", "data-errormessage-value-missing": "*University Required", "onblur": "$(this).validationEngine('validate');"
}
}
this is the sample colModel of University,
here the field which we want to submit to controller should be given in name attribute,
and the field which is to be displayed in grid should be given in jsonmap attribute.
Since the upgrade to grails 2.3.5, a strange behaviour of the hibernate plugin (moved from version 3.6.10.6 to 3.6.10.7) results in a bean error at runtime:
14-01-22 16:22:54,064 ERROR [GrailsContextLoader] - Error initializing the application: Error creating bean with name 'xxx.xxxx.StatisticsValidator': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void org.codehaus.groovy.grails.orm.hibernate.validation.HibernateDomainClassValidator.setProxyHandler(org.codehaus.groovy.grails.support.proxy.ProxyHandler); nested exception is java.lang.NoSuchMethodError: org.springframework.util.ClassUtils.determineCommonAncestor(Ljava/lang/Class;Ljava/lang/Class;)Ljava/lang/Class;
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.xxx.xxxx.StatisticsValidator': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void org.codehaus.groovy.grails.orm.hibernate.validation.HibernateDomainClassValidator.setProxyHandler(org.codehaus.groovy.grails.support.proxy.ProxyHandler); nested exception is java.lang.NoSuchMethodError: org.springframework.util.ClassUtils.determineCommonAncestor(Ljava/lang/Class;Ljava/lang/Class;)Ljava/lang/Class;
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:724)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void org.codehaus.groovy.grails.orm.hibernate.validation.HibernateDomainClassValidator.setProxyHandler(org.codehaus.groovy.grails.support.proxy.ProxyHandler); nested exception is java.lang.NoSuchMethodError: org.springframework.util.ClassUtils.determineCommonAncestor(Ljava/lang/Class;Ljava/lang/Class;)Ljava/lang/Class;
Here is the Statistics domain class which is concerned, even if nothing has been changed since grails 2.3.4:
class Statistics implements Serializable {
static belongsTo = [profile: Profile]
Profile profile
String email
String dbkey
String clientCode
String affiliatesNbr
String freeStorageBonus
String freeUsersBonus
String storageUsed
String storageAvailable
String quotaUsersCurrent
String quotaUsersAvailable
String comments
Date processedDate
static constraints = {
profile unique: true, nullable: false, blank: false
email email: true, maxSize: 80, nullable: false, blank: false
dbkey maxSize: 80, nullable: false, blank: false
clientCode maxSize: 40, nullable: false, blank: false
affiliatesNbr maxSize: 40, nullable: true, blank: true
freeStorageBonus maxSize: 40, nullable: true, blank: true
freeUsersBonus maxSize: 40, nullable: true, blank: true
storageUsed maxSize: 40, nullable: true, blank: true
storageAvailable maxSize: 40, nullable: true, blank: true
quotaUsersCurrent maxSize: 40, nullable: true, blank: true
quotaUsersAvailable maxSize: 40, nullable: true, blank: true
comments maxSize: 180, nullable: true, blank: true
processedDate nullable: true, blank: true
}
Below the list of plugins used:
plugins {
build ":tomcat:7.0.50"
runtime ":hibernate:3.6.10.7"
runtime ":database-migration:1.3.8"
runtime ":resources:1.2.1"
runtime ":jquery:1.8.3" //jquery:1.10.2
compile ":scaffolding:2.0.1"
compile ":cache:1.1.1"
compile ":bean-fields:1.0"
compile ":csv:0.3.1"
compile ":famfamfam:1.0.1"
compile ":form-helper:0.2.8"
compile ":google-chart:0.5.2"
compile ":google-visualization:0.6.2"
compile ":jcaptcha:1.2.1"
compile ":jdbc-pool:7.0.47"
compile ":jquery-ui:1.8.24"
compile ":navigation:1.3.2"
compile ":quartz:1.0.1" //1.0.1
compile ":richui:0.8"
compile ":spring-security-core:2.0-RC2"
compile ":webflow:2.0.8.1"
compile ":rendering:0.4.4"
compile ":modernizr:2.7.1.1"
compile ":spring-security-acl:2.0-RC1"
compile ":pdf-viewer:0.1"
compile ":taggable:1.0.1"
compile ":executor:0.3"
compile ":gmetrics:0.3.1"
compile ":lesscss-resources:1.3.3"
compile ":pretty-size:0.2"
compile ":mysql-connectorj:5.1.22.1"
compile ":font-awesome-resources:4.0.3.0"
compile ":aws-sdk:1.6.12"
compile ":aws:1.6.7.5"
}