I want add unified response by modifying ApiResource. It is a HTTP body, it always contains json data below:
{
data: T
message: String
status: Int
}
I tried to add
val gson = Gson()
val stewardResponse = gson.fromJson(
response.body().toString(),
StewardResponse::class.java
)
if (body == null || response.code() == 204) {
ApiEmptyResponse()
} else {
ApiSuccessResponse(
body = stewardResponse.data,
linkHeader = response.headers()?.get("link")
)
}
but failed with the tip:
Type mismatch.
Required: ApiResponse<T> Found: ApiSuccessResponse<Any?>
Related
I'm trying to parse a csv file and map it onto a data class. I've setup some validations for the columns and I'm testing it by sending incorrect values for those columns. opencsv throws a generic exception
Basic instantiation of the given bean type (and subordinate beans created through recursion, if applicable) was determined to be impossible.
Code details
Data class:
data class UserInfo(
#CsvBindByName(column = "Id", required = true) val id: Long,
#CsvBindByName(column = "FirstName", required = true) val firstName: String,
#CsvBindByName(column = "LastName", required = true) val lastName: String,
#CsvBindByName(column = "Email", required = true) val email: String,
#CsvBindByName(column = "PhoneNumber", required = true) val phoneNumber: String,
#PreAssignmentValidator(
validator = MustMatchRegexExpression::class, paramString = "^[0-9]{10}$")
#CsvBindByName(column = "Age", required = true)
val age: Int
)
csv parsing logic
fun uploadCsvFile(file: MultipartFile): List<UserInfo> {
throwIfFileEmpty(file)
var fileReader: BufferedReader? = null
try {
fileReader = BufferedReader(InputStreamReader(file.inputStream))
val csvToBean = createCSVToBean(fileReader)
val mappingStrategy: HeaderColumnNameMappingStrategy<Any> =
HeaderColumnNameMappingStrategy<Any>()
mappingStrategy.type = UserInfo::class.java
val userInfos = csvToBean.parse()
userInfos.stream().forEach { user -> println("Parsed data:$user") }
csvToBean.capturedExceptions.stream().forEach { ex -> println(ex.message) }
return userInfos
} catch (ex: Exception) {
throw CsvImportException("Error during csv import")
} finally {
closeFileReader(fileReader)
}
}
private fun createCSVToBean(fileReader: BufferedReader?): CsvToBean<UserInfo> =
CsvToBeanBuilder<UserInfo>(fileReader)
.withType(UserInfo::class.java)
.withThrowExceptions(false)
.withIgnoreLeadingWhiteSpace(true)
.build()
I'm looking for the proper error message for the validation / missing field so that I can communicate it to the error response.
I have an issue where i have a method where i am checking the payload has the attributes or not. When i am sending my payload i want to check that the user dont have inserted attributes which not allowed in the payload.
My entity class:
#Entity
data class ProjectAssociated(
#Id
#GeneratedValue(generator = "uuid2")
#GenericGenerator(name = "uuid2", strategy = "uuid2")
#Column(columnDefinition = "BINARY(16)")
var id: UUID? = null,
#Column(columnDefinition = "BINARY(16)")
var projectId: UUID? = null,
#Column(columnDefinition = "BINARY(16)")
var associatedProjectId: UUID? = null
)
My Service class:
fun addAssociatedProjectByProjectId(
projectId: UUID,
projectAssociatedList: MutableList<ProjectAssociated>
): MutableList<ProjectAssociated> {
if (projectAssociatedList.isNotEmpty()) {
println(projectAssociatedList)
if (!projectAssociatedList.map { it.id }.isNullOrEmpty()) {
val errorMessage = "Not allowed to provide parameter 'id' in this request"
throw UserInputValidationException(errorMessage)
}
if (!projectAssociatedList.map { it.projectId }.isNullOrEmpty()) {
val errorMessage = "Not allowed to provide parameter 'projectId' in this request"
throw UserInputValidationException(errorMessage)
}
val checkIds = projectAssociatedList.map {
projectRepository.existsById(it.associatedProjectId)
}
if (checkIds.contains(false)) {
val errorMessage = "One or more ID 'associatedProjectId' not exists"
throw UserInputValidationException(errorMessage)
}
}
return projectAssociatedList.map {
projectAssociatedRepository.save(
ProjectAssociated(
null,
projectId,
it.associatedProjectId
)
)
}.toMutableList()
}
My Controller class:
#ApiOperation("Add associated Projects to a specific Project")
#PostMapping(path = ["/project-associated"], consumes = [MediaType.APPLICATION_JSON_VALUE])
fun createAssociatedProjectList(
#ApiParam("The id of the Project", required = true)
#RequestParam("id")
id: UUID,
#ApiParam("JSON object representing the ProjectAssociated")
#RequestBody projectAssociated: MutableList<ProjectAssociated>
): ResponseEntity<WrappedResponse<MutableList<ProjectAssociated>>> {
val createdProjectAssociatedList = projectService.addAssociatedProjectByProjectId(id, projectAssociated)
return ResponseEntity
.status(201)
.location(URI.create("$id/project-associated"))
.body(
ResponseDto(
code = 201,
data = PageDto(list = mutableListOf(createdProjectAssociatedList))
).validated()
)
}
But when i try to send this payload with the project id in #RequestParam:
[
{
"associatedProjectId": "7fe40f90-5178-11ea-9136-1b65a920a5d9"
},
{
"associatedProjectId": "7fe8aaaa-5178-11ea-9136-1b65a920a5d9"
}
]
I have a custom exception where i tell the user if projectId or the id is in the payload that is now allowed to have it in the payload. When i try to POST the payload example above it tells me that projectId or id is in the request? How can that be?
I also printed out the list before if checks:
[ProjectAssociated(id=null, projectId=null, associatedProjectId=7fe40f90-5178-11ea-9136-1b65a920a5d9), ProjectAssociated(id=null, projectId=null, associatedProjectId=7fe8aaaa-5178-11ea-9136-1b65a920a5d9)]
What am I doing wrong?
Thanks for the help!
In the block projectAssociatedList.map { it.id } you are mapping your list to something like [null, null] and it is not null or empty.
So, the complete condition !projectAssociatedList.map { it.id }.isNullOrEmpty() returns true.
If you want to continue using the same logic, you should use !projectAssociatedList.mapNotNull { it.id }.isNullOrEmpty() instead.
The mapNotNull function will filter the null values and output a list just with the not null values. If there is only null values, the list will be empty.
But, a simpler and expressive way to check if there is any not null attribute in a list of objects could be projectAssociatedList.any { it.id != null }
I have a ldap method that returns all users that are in it (almost 1300 users) and I want to return them by page, similar to what PagingAndSortingRepository does in Springboot:
If I have this endpoint ( users/?page=0&size=1 )and I wnat to return on page 0 just 1 entry.
Is there any way to do that?
Currently I have this but it doesn´t work:
SearchRequest searchRequest = new SearchRequest(ldapConfig.getBaseDn(), SearchScope.SUB,
Filter.createEqualityFilter("objectClass", "person"));
ASN1OctetString resumeCookie = null;
while (true) {
searchRequest.setControls(new SimplePagedResultsControl(pageable.getPageSize(), resumeCookie));
SearchResult searchResult = ldapConnection.search(searchRequest);
numSearches++;
totalEntriesReturned += searchResult.getEntryCount();
for (SearchResultEntry e : searchResult.getSearchEntries()) {
String[] completeDN = UaaUtils.searchCnInDn(e.getDN());
String[] username = completeDN[0].split("=");
UserEntity u = new UserEntity(username[1]);
list.add(u);
System.out.println("TESTE");
}
SimplePagedResultsControl responseControl = SimplePagedResultsControl.get(searchResult);
if (responseControl.moreResultsToReturn()) {
// The resume cookie can be included in the simple paged results
// control included in the next search to get the next page of results.
System.out.println("Antes "+resumeCookie);
resumeCookie = responseControl.getCookie();
System.out.println("Depois "+resumeCookie);
} else {
break;
}
Page<UserEntity> newPage = new PageImpl<>(list, pageable, totalEntriesReturned);
System.out.println("content " + newPage.getContent());
System.out.println("total elements " + newPage.getTotalElements());
System.out.println(totalEntriesReturned);
}
I'm unsure if this is the proper way, but here's how I went about it:
public PaginatedLookup getAll(String page, String perPage) {
PagedResultsCookie cookie = null;
List<LdapUser> results;
try {
if ( page != null ) {
cookie = new PagedResultsCookie(Hex.decode(page));
} // end if
Integer pageSize = perPage != null ? Integer.parseInt(perPage) : PROCESSOR_PAGE_SIZE;
PagedResultsDirContextProcessor processor = new PagedResultsDirContextProcessor(pageSize, cookie);
LdapName base = LdapUtils.emptyLdapName();
SearchControls sc = new SearchControls();
sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
sc.setTimeLimit(THREE_SECONDS);
sc.setCountLimit(pageSize);
sc.setReturningAttributes(new String[]{"cn", "title"});
results = ldapTemplate.search(base, filter.encode(), sc, new PersonAttributesMapper(), processor);
cookie = processor.getCookie();
} catch ( Exception e ) {
log.error(e.getMessage());
return null;
} // end try-catch
String nextPage = null;
if ( cookie != null && cookie.getCookie() != null ) {
nextPage = new String(Hex.encode(cookie.getCookie()));
} // end if
return new PaginatedLookup(nextPage, results);
}
The main issue I kept on hitting was trying to get the cookie as something that could be sent to the client, which is where my Hex.decode and Hex.encode came in handy.
PersonAttributesMapper is a private mapper that I have to make the fields more human readable, and PaginatedLookup is a custom class I use for API responses.
I have byte array byteImg but I want render in my controller jpeg from byte array:
def getSelfie = new HTTPBuilder()
getSelfie.request(fullSelfieUrl, GET, JSON) { req ->
headers.'X-DreamFactory-Session-Token' = session_id
headers.'X-DreamFactory-Application-Name' = 'checkReg'
response.success = { resp, reader ->
assert resp.statusLine.statusCode == 200
println "Get response: ${resp.statusLine}"
println "Content-Type: ${resp.headers.'Content-Type'}"
resp = reader as grails.converters.JSON
String str = resp.toString()
JSONObject jsonObject = new JSONObject(str)
selfieRend = jsonObject.getString("selfie")
byteImg = selfieRend.getBytes()
render byteImg
return byteImg
}
response.'404' = {
println 'Information not found'
}
}
how to do it? Thank you so much
I haven't tested it but as per wiki this should work:
def getSelfie(){
def http = new AsyncHTTPBuilder(
poolSize : 4,
uri : fullSelfieUrl,
contentType : ContentType.JSON )
def result = http.get() { resp, json -> json.selfie.bytes }
while( !result.done ) Thread.sleep 1000
def bytes = result.get()
response.setHeader 'Content-disposition', "inline; filename=someName.jpg"
response.setHeader 'Content-Type', 'image/jpg'
response.outputStream.withStream{ it << bytes }
}
If I have a Backbone model who's defaults object looks like this:
defaults {
"id" : null
"name" : null,
"url" : null,
"admin" : {
"id" : null,
"email" : null
}
}
is there a recommended way to validate the presence of something like admin[id]? We've written a method that makes the attempt, but it keeps puking (especially on new model creation) on null values, or if data is fetched from our DB with null values that are expected to be required (we are laying this app on top of existing data).
Here's our method for validating the presence of required fields:
validatePresence = function(requiredAttrs, submittedAttrs, errorsArr) {
var regex = new RegExp(/[a-zA-Z0-9_]+|(?=\[\])/g),
attrStack = null,
val = null,
name = null;
for( var l = requiredAttrs.length; --l >= 0; ) {
attrStack = requiredAttrs[l].match(regex);
val = submittedAttrs[attrStack.shift()];
while(attrStack.length > 0) {
console.log(requiredAttrs[l]);
val = val[attrStack.shift()];
}
if( val === undefined ) { continue; }
name = requiredAttrs[l];
if( val === null || !val.length) {
if( !errorsArr[name] ) {
errorsArr[name] = [];
}
errorsArr[name].push("Oops, this can't be empty");
}
}
return errorsArr;
}
And here's the way we call it from within a BB model:
validate: function(attrs) {
var requiredAttributes = ["name","admin[id]"],
errors = {};
errors = validatePresence(requiredAttributes, attrs, errors);
}
That method likes to choke on things like "admin[id]". Any help is apprecaited.
If you're not dead set on the bracket notation for your required attributes, you could draw some inspiration from this Q&A to simplify your validation.
Let's add a helper method to _ to extract the value of a given attribute:
_.findprop = function(obj, path) {
var args = path.split('.'), i, l=args.length;
for (i=0; i<l; i++) {
if (!obj.hasOwnProperty(args[i]))
return;
obj = obj[args[i]];
}
return obj;
}
Your validate method can then be rewritten as:
validate: function(attrs) {
var requiredAttributes = ["name","admin.id"],
errors = {}, i, l, v, attr;
for (i=0, l=requiredAttributes.length; i<l; i++) {
attr = requiredAttributes[i];
v = _.findprop(attrs, attr);
//checks if the value is truthy, to be adapted to your needs
if (v) continue;
errors[attr] = errors[attr] || [];
errors[attr].push("Oops, this can't be empty");
}
return errors;
}
And a demo http://jsfiddle.net/FrtHb/2/