I was looking around for the proper definition to use for allowing multiple file upload in my operation description using annotations (2.x).
The only working solution I found was following under
#POST
#Operation(
...
requestBody = #RequestBody(
description = "files to upload",
content = #Content(
mediaType = MediaType.MULTIPART_FORM_DATA,
schema = #Schema(implementation = UploadFile.class)
)
),
...
)
...
finally I only had to declare the UploadFile class (as inner class for example)
private class UploadFile {
#ArraySchema(schema = #Schema(format = "binary", type = "string"))
public String[] files;
}
so the trick was to use above, and it then worked like a charm in the swagger ui so it recognized it as I would have expected.
I hope that might help others.
Related
Although this or similar questions have been asked before for much older versions of grails, I wonder what would be the best approach to access a configuration value from application.yml in a grails domain class with modern grails 4.0.3.
So, let's say we have a voucher.groovy like
class Voucher implements HibernateEntity<Voucher> {
...
Date reservedAt
static transients = ['validUntil']
Date getValidUntil() {
Integer expirationTime = // TODO: fill in the configuration value
DateTime expirationDateTime = new DateTime(this.reservedAt)
.plusDays(expirationTime)
.withHourOfDay(23)
.withMinuteOfHour(59)
.withSecondOfMinute(59)
.withMillisOfSecond(999)
return expirationDateTime.toDate()
}
}
and a configuration value named voucher.expirationTime in our application.yml like
...
voucher.expirationTime: 10
...
How could I access the config value in my getValidUntil() method?
EDIT
As #JeffScottBrown mentioned in his comment, you shouldn't access config values in your domain class. So I ended up with his suggested apporach using a custom gsp tag. (See the answer below)
How to access configuration values in domain classes? You shouldn't!
In my case I needed to display a derived value as a combination of a domain attribute and a configuration value reservedAt + expirationTime.
Thanks to Jeff Scott Brown's comment, I managed to create a custom gsp tag for my purpose:
class VoucherTagLib {
static returnObjectForTags = ['validUntil']
static namespace = "voucher"
#Value('${voucher.expirationTime}')
Integer expirationTime
GrailsTagDateHelper grailsTagDateHelper
def validUntil = { attrs, body ->
Date reservedAt = attrs.reservedAt
String style = attrs.style ?: "SHORT"
Locale locale = GrailsWebRequest.lookup().getLocale()
if (locale == null) {
locale = Locale.getDefault()
}
def timeZone = grailsTagDateHelper.getTimeZone()
def dateFormat = grailsTagDateHelper.getDateFormat(style, timeZone, locale)
DateTime expirationDateTime = new DateTime(reservedAt)
.plusDays(expirationTime - 1)
.withHourOfDay(23)
.withMinuteOfHour(59)
.withSecondOfMinute(59)
.withMillisOfSecond(999)
return grailsTagDateHelper.format(dateFormat, expirationDateTime.toDate())
}
}
Although this might not be the answer that you are looking for, I hope this will help others with a similar problem!
Is there a better way to set bearer like a global config rather than setting it each time like this:
restClient.setBearerAuth(TokenStore.getInstance().getLocalToken());
The same for root url, is there a global config rather than setting it like this:
String root= Application.getInstance().getApplicationContext().getResources().getString(R.string.whiteLabelApiBaseHost)
restClient.setRootUrl(root);
In retrofit, there is something like this:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Application.getInstance().getApplicationContext()
.getResources().getString(R.string.whiteLabelApiBaseHost))
Any idea?
To set root url you can use this method, substituting the string with a constant
#Rest(rootUrl = "http://company.com/ajax/services", converters = { MappingJackson2HttpMessageConverter.class }, interceptors = MyAuthInterceptor.class)
public interface MyRestClient {
#Get("/events")
EventList getEvents();
}
Note that we set an interceptor in the arguments of the #Rest annotation.
So create a class like this:
#EBean(scope = Scope.Singleton)
public class MyAuthInterceptor implements ClientHttpRequestInterceptor {
#Bean
MyAuthStore authStore;
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
HttpHeaders headers = request.getHeaders();
HttpAuthentication auth = new HttpBasicAuthentication(authStore.getUsername(), authStore.getPassword());
headers.setAuthorization(auth);
return execution.execute(request, body);
}
}
Now before executing request MyAuthInterceptor.intercept() is called and you can set your authentication data as you prefer
In your main build.gradle file you can add inside android element
productFlavors {
development {
buildConfigField "String", "SERVICE_URL_BASE", "\"dev.xxx.com/rest\""
}
test {
buildConfigField "String", "SERVICE_URL_BASE", "\"test.xxx.com/rest\""
}
production {
buildConfigField "String", "SERVICE_URL_BASE", "\"production.xxx.com/rest\""
}
}
Then in your #Rest annotation you can use this code to get current flavor value:
#Rest(rootUrl = "https://" + BuildConfig.SERVICE_URL_BASE)
Now you can select what build variant to use (variant = flavor + buildType) to use desired value. To select variant you can use corresponding view, it should be present on the left of android studio.
This technique is useful to avoid creating flavor's package tree only to use different variabiles
I have an ODataController with a Get method as such:
public IHttpActionResult Get(ODataQueryOptions<MyModel> queryOptions) {
IQueryable<MyModel> models = _Models.AsQueryable(); // _Models Defined in Controller as List<MyModel> and is already populated with nested data for both .LevelOne and .LevelOne.LevelTwo which are two other Lists.
Uri fullrequest = Request.GetRequestContext().Url.Request.RequestUri; // http://localhost:8080/odata/Root?$expand=LevelOne($expand=LevelTwo)
Uri serviceroot = new Uri(controller.GetLeftPart(UriPartial.Path).Replace("/Root", "")); // http://localhost:8080/odata
String metadata = service + "/$metadata"; // http://localhost:8080/odata/$metadata
IEdmModel model = EdmxReader.Parse(XmlTextReader.Create(metadata));
ODataUriParser parser = new ODataUriParser(model, serviceroot, fullrequest);
SelectExpandClause selectAndExpand = parser.ParseSelectAndExpand();
//Only one of the two below lines is ever commented in...
Request.ODataProperties().SelectExpandClause = queryOptions.SelectExpand.SelectExpandClause; // This line will work
Request.ODataProperties().SelectExpandClause = selectAndExpand; // This line will not work
return Ok(models);
}
using my manually parsed selectAndExpand does not expand the dataset, but using the predefined queryOptions one does. Any ideas why? Both objects appear to contain the same information while viewed in the debugger, but I must be missing something. I want to be able to parse the URI myself, without the need for the ODataQueryOptions at all.
What I ended up doing, was building a new ODataQueryOptions object based off the original request, and then pulling just the SelectExpandClause from that. It doesn't answer my initial question, but it is a somewhat working solution for not having to pass in a ODataQueryOptions parameter. See my Code below:
public IHttpActionResult Get() {
//Get Queryable Item (in this case just a list made queryable)
IQueryable<MyModel> models = _Models.AsQueryable();
//Create new ODataQueryContext based off initial request (required to create ODataQueryOptions)
ODataQueryContext selectAndExpandContext = new ODataQueryContext(Request.ODataProperties().Model, typeof(MyModel), Request.ODataProperties().Path);
//Create new ODataQueryOptions based off new context and original request
ODataQueryOptions<Employee> selectAndExpandOptions = new ODataQueryOptions<Employee>(selectAndExpandContext, Request);
//Attach Select + Expand options to be processed
if (selectAndExpandOptions.SelectExpand != null) {
Request.ODataProperties().SelectExpandClause = selectAndExpandOptions.SelectExpand.SelectExpandClause;
}
return Ok(models);
}
I am using opencsv in my Grails application to export attributes from my Person domain class to CSV. I am receiving the following error, however:
Servlet.service() for servlet [default] in context with path [/myapp] threw exception [Request processing failed; nested exception is org.codehaus.groovy.grails.web.pages.exceptions.GroovyPagesException: Error processing GroovyPageView: getOutputStream() has already been called for this response] with root cause
Message: getOutputStream() has already been called for this response
From searching online, I think the answer may be to implement some responseComplete() method somewhere for the HttpServletResponse response. However, I am not sure how to do this. Any ideas? Here is my code:
def export = {
def course = Course.get(params.id)
if(course){
def persons = course ? Person.findAllByCourse(course) : []
response.setHeader("Content-disposition",
"attachment; filename=people.csv")
response.contentType = "text/csv"
def out = response.outputStream
out.withWriter { writer ->
String[] properties = new String[3]
def csvWriter = new CSVWriter(writer)
persons.each { person ->
properties[0] = person.firstName
properties[1] = person.lastName
properties[2] = person.email
properties[3] = person.phone
properties[4] = person.address1
properties[5] = person.address2
properties[6] = person.city
properties[7] = person.state
properties[8] = person.zip5
csvWriter.writeNext(properties)
}
csvWriter.flush()
}
}
Your problem probably stems from explicitly writing to the output stream in your controller, followed by the default behavior of GSP rendering upon returning from your action. You might check How to prevent Grails from rendering the default view? for another case of this, with a couple fixes. I don't have grails on the machine I'm on currently to recreate the issue, but sounds like adding an explicit return null to at the end of the closure may help. Or producing some token output or a 200 status code via render.
You have to change this proprity String[] properties = new String[3] by String[] properties = new String[9].
It works for me.
Can any one please help me how to get the real file name from Struts2 MultiPartRequestWrapper.
MultiPartRequestWrapper multiWrapper =
(MultiPartRequestWrapper) ServletActionContext.getRequest();
Enumeration fileParameterNames = multiWrapper.getFileParameterNames();
if(fileParameterNames.hasMoreElements()){
String inputValue = (String) fileParameterNames.nextElement();
File[] files = multiWrapper.getFiles(inputValue);
for (File cf : files) {
System.out.println(cf.getParentFile().getName());
System.out.println("cf is : " + cf.getName());
System.out.println("cf is : " + cf.toURI().getPath());
File.createTempFile(cf.getName(),"");
}
}
I can see original file name, type, size from "fileParameterNames" but when get file I can only see tempfile with upload_xxxxxxxxx.tmp.
How can I get original file name from the File.
Advance thanks for your help.
Why are you doing all that?
See the file upload FAQ and details pages. All you need to do is provide the appropriate action properties:
public void setUploaded(File myDoc);
public void setUploadedContentType(String contentType);
public void setUploadedFileName(String filename);
and use the file upload interceptor, which is included in the default stack.
Note that different browsers send different information; some only send the original filename, while some send the complete path.
You have to use : multiWrapper.getFileNames("file")[0]
Where "file" is the name of the file control.
var fd = new FormData();
fd.append('file', files[i]);