REST Client Grails Groovy unable to resolve class RestClientBuilder - spring

I have an empty project created using GGTS, my app runs fine, I can see the views and navigate through them fine.
I need con call a REST api and consume the data provided, I read and added the necessary plug in to the BuildConfig file under the dependencies and then under the plugins section, none of them seem to work.
compile ":rest-client-builder:2.0.0"
I've created a controller, I'm not sure where to add the import here, so I've tried:
package myapp
class UserController {
def index() {
import grails.plugins.rest.client.RestBuilder
String url = "https://foo.com/batch/$id"
def resp = new RestBuilder().get(url) { header 'Authorization', 'Basic base64EncodedUsername&Password' }
render resp
}
but I get the error: unable to resolve class....
The API is returning JSON data, what I;ve done so far is just to create a new Grails project, add controller, add view and then the dependency.
I've cleaned an built the project several times but the error remains.
Thanks for your help.

Import goes at the top
After the package line
And before the class line
Also, depending on your version of grails, you might want to move of ggts... Not sure it's supported any more...

I think that the problem is in your build.gradle dependency definition.
Insert the next line to your build.gradle file and I think that will be helpful:
compile "org.grails.plugins:rest-client-builder:2.1.1"
For more information follow the grails plugin documentation.
Please be aware that all the business logic should be placed in the service layer and not in the controller. It is a best practice to keep your controller lean as possible.
Another best practice is to define the following line:
String url = "https://foo.com/batch/$id"
in the beggining of the controller as static final String
static final String url = "https://foo.com/batch/"
and add the $id when needed in the code.
Here is how that should be called inside the method:
String url = "${url}/{$id}"

Related

Hibernate Search 6 #ProjectionConstructor not working

I am experimenting the projection features of Hibernatesearch 6.2.0.Alpha1 before integrating our existing app.
I have created a spring-boot project with JHIPSTER sample project. And added the Hibernate-search dependencies and configurations in both POM.XML and application*.yml. Using JHipster because it helps me with the boilerplate code and fake data.
Have configured pom.xml with both -parameters and jandex. Application runs successfully and loads the data into the database. And i am able to mass Index with the utility we wrote as per the documents.
However when try to search the data with projections we are recieving the error Exception in searchWithProjection() with cause = 'NULL' and exception = 'HSEARCH700112: Invalid object class for projection: com.sample.shop.service.projections.dto.Address. Make sure that this class is mapped correctly, either through annotations (#ProjectionConstructor) or programmatic mapping. If it is, make sure the class is included in a Jandex index made available to Hibernate Search.'. The same query/logic works perfectly fine if we search without projections.
Ex. if you view the files AddressResource.java & AddressService.java in the above linked repository; you can find 2 implementations for projections and no-projections respectively. while the one without projections works perfectly fine the one with projects is throwing the error.
I feel it might be some configuration issue, however not able to figure-out myself. Appreciate your help on configuration / code approach.
Please be informed that I have gone through the follwoing tickets already:
Hibernate Search 6 combine projections not working
Single return type in Hibernate Search
Thanks for your reproducer. It's a bug: https://hibernate.atlassian.net/browse/HSEARCH-4724
I suggested a workaround here: https://github.com/anothergoodguy/spring-data-hibernate-search/pull/1
In short:
Add this class to your application:
package com.sample.shop.config;
import java.net.URISyntaxException;
import java.nio.file.Path;
import org.hibernate.search.mapper.orm.mapping.HibernateOrmMappingConfigurationContext;
import org.hibernate.search.mapper.orm.mapping.HibernateOrmSearchMappingConfigurer;
import org.hibernate.search.util.common.jar.impl.JandexUtils;
import org.springframework.stereotype.Component;
#Component("searchMappingConfigurer")
public class HibernateSearchMappingConfigurer implements HibernateOrmSearchMappingConfigurer {
#Override
public void configure(HibernateOrmMappingConfigurationContext context) {
// Workaround for https://hibernate.atlassian.net/browse/HSEARCH-4724
// => Hibernate Search doesn't seem to find the Jandex index in the fat JAR.
try {
var classesUri = getClass().getProtectionDomain().getCodeSource().getLocation().toURI();
var ssp = classesUri.getSchemeSpecificPart();
var jarpath = Path.of(ssp.substring(ssp.indexOf(":") + 1, ssp.indexOf("!")));
context.annotationMapping().add(JandexUtils.readIndex(jarpath).get());
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
}
Reference it in your configuration:
jpa:
properties:
hibernate.search.mapping.configurer: bean:searchMappingConfigurer
And voilĂ .
Note it's just a workaround and relies on internal code that may break at any time. But, well, at least it works, so it's fine until the bug gets fixed.
Here are the instructions to run the application:
All the needed ecosystem like Elasticsearch, kibana and MySql are added in eco.yml file under src/main/docker/eco.yml
Please use the following command to bring the ecosystem up docker-compose -f src/main/docker/eco.yml up -d && docker-compose -f src/main/docker/eco.yml logs -f
On a different termina tab/window, Build the application with the following command ./mvnw clean package -Pprod,api-docs -Dskip.Tests -Dmaven.test.skip=true
to run the application run the following command java -jar target/shop-app-0.0.1-SNAPSHOT.jar
Once the application is started, it will show that it's listneing on [http://localhost:8080]. Please open the same url on the browser and login with the default administrator User:admin and Password:admin.
Then please navigate to swagger from Administrator menu and API menu-item.
We need to Mass-Index the fake data that's is already loaded from swagger from same swagger window: by executing the post on /api/mass/index on the resource Elastic Search Mass Indexing API
Then please go to the address-resource :
Request without Projections access /api/_search/addresses with
query string aa - This will result in success
Request with Projections access /_search/addresses/projection with same query string aa - This will result in failure

Springboot read json and create menu link out of it

I need to read a json file with multiple linkname and url then create a menu link mapping out of it.
Menu
linkname1: This is a link1
linkname2: This is a link2
Using org.apache.model.rest.RestDefinition method if possible, any idea?
I have to put
#Controller
#RequestMapping("/xxxx")
On the main class
I have to put
#GetMapping()
public static RestDefinition
But it only run in eclipse and it compile with no error, but if you run, you will have error. I just decided to rewrite it all in spring-boot without RestDefinition and old java programs.

swagger codegen add #JacksonXmlElementWrapper(useWrapping = false) annotation to a single field

I'm currently using swagger codegen using yml to generate my models However I have one field, that is a List<Object> that needs to have the #JacksonXmlElementWrapper(useWrapping = false). I can see the #JacksonXmlElementWrapper in POJO.mustache but not in model.mustache. Does anyone know what to add in the yaml file or anywhere else so that field gets generated with that annotation? Thanks. I'm using spring-java language with gradle. I need this to be generated during build. so minimal changes are preferred.
According to the readme on their git, Swagger Codegen mention ways to do this:
https://github.com/swagger-api/swagger-codegen/blob/master/README.md
since you're using gradle:
We can use a custom template for the code generation as follows:
// build.gradle
swaggerSources {
inputFile = file('{name of your file}.yaml')
xyz {
language = 'spring'
// template directory path
templateDir = file('templates/{name of your custom directory}')
}
}
inside templates/{name of your custom directory}, you can store your custom mustache files, as in your case, all you have to do is download the required spring templates from git (e.g. this link is for pojo.mustache)
and add in the required changes to the template, along with the project and libraries folder. Run gradle build and it should generate.
There is a much simpler workaround however, where you can just use your own pojo class and add this in your existing config.json and remove the earlier entry for that model in your yaml file (of course):
"importMappings" : {
"{replace with className}": "{replace with packageName}.{replace with className}"
}
Hope this helps.

Render a template as string in a service in Grails 3 rest-api profile app

I've created a Grails 3.2.1 app with rest-api profile and want to render a GSP template as a String. For this I first added, apply plugin:"org.grails.grails-gsp" in build.gradle then based on the code of ResponseRenderer, I tried following to render my GSP template as:
def viewResolver = applicationContext.getBean(CompositeViewResolver.BEAN_NAME, CompositeViewResolver)
View view = viewResolver.resolveView("/email-templates/signup", null)
But the view object is always null. Then I tried the following as well without success:
[ViewResolverComposite, GroovyMarkupViewResolver, GenericGroovyTemplateViewResolver].each {
def viewResolver = applicationContext.getBean(it)
View view = viewResolver.resolveViewName("/email-templates/signup", null)
println view?.dump()
}
My template is located at grails-app/views/emails-templates/_signup.gsp.
In Grails 2, it was quite simple by injecting groovyPageRenderer bean of type PageRenderer but I think, that bean and class is no longer used in Grails 3.
For Grails 3 app created with web profile, they can always use the groovyPageRenderer as given in the link Grails render view from service?.
And for the app created with rest-api profile, they just need to add the following in build.gradle under dependencies block:
compile "org.grails:grails-plugin-gsp:3.2.1"
And the above link will also work as is.
Just for the sake of description, inject the bean and use the render method:
PageRenderer groovyPageRenderer
def someMethod() {
println groovyPageRenderer.render(template: "/email-templates/signup", model: [foo: "bar"])
}
For Grails 3.3.x, few plugins have been externalized and artefact ids has changed.
Please refer here.
So, to make sure that groovyPageRenderer bean is registered, add
compile "org.grails.plugins:gsp"
to the dependencies block in build.gradle instead of
compile "org.grails:grails-plugin-gsp"
Just to make sure the plugin is initialised successfully in your app, add
logger('grails.plugins', TRACE)
in the logback.groovy file. You should see something like this in the console logs.
Grails plug-in [groovyPages] with version [3.3.x] loaded successfully
For compiling GSP files and adding it to the war/jar package, add
apply plugin:"org.grails.grails-gsp"
to your build.gradle file.
I hope this helps.

Override a Service in Grails using Spring Bean declaration

I am creating a new plugin containing CustomService which is intended to replace an existing service from an existing plugin. Following the pattern found in custom security implementations and shown here, I've added the configuration to the resources.groovy, oldService(path.to.new.CustomService). I've also tried adding all injected classes into the closure for this service.
(Actual service names are RegistrationPersonRegistrationCompositeService and NewRegistrationPersonRegistrationCompositeService in code block)
I dont want the original application code to have any reference to the new plugin. However, BuildConfig at the application level will require plugin.location entry. My resource.groovy mods are in the new plugin. I have not had success in this endeavor. Am I modifying the wrong resources.groovy? If this change is required in the original application code, I've lost the ability to leave the original code unaltered. I'm not extending the original Service nor using override annotation. My intent is to replace the service (Spring bean) on start-up. The new plugin has a dependency on the old plugin in an attempt to manage order of operations in loading these classes.
Does it matter that the old service is previously injected in a controller? this would require me to override the controller in the new plugin in the same fashion and inject the correct service for desired behavior?
I've found documentation showing that within a plugin, the resources.groovy will be ignored. Also, building the resources.groovy into a war is problematic. I have not found a solution. I'm getting no error that I can share, just that the desired behavior is missing; the original service is handling the requests.
//was resource.groovy - now renamed to serviceOverRide.groovy - still located in \grails-app\conf\spring of plugin
//tried this with and without the BeanBuilder. Theory: I'm missing the autowire somehow
import org.springframework.context.ApplicationContext
import grails.spring.BeanBuilder
def bb = new BeanBuilder()
bb.beans {
registrationPersonRegistrationCompositeService(path.to.services.registration.NewRegistrationPersonRegistrationCompositeService) { bean ->
bean.autowire = true
registrationRestrictionCompositeService = ref("registrationRestrictionCompositeService")
registrationPersonTermVerificationService = ref("registrationPersonTermVerificationService")
}
classRegistrationController(path.to.services.registration.ClassRegistrationController) { bean ->
bean.autowire = true
selfServiceLookupService = ref("selfServiceLookupService")
registrationPersonRegistrationCompositeService = ref("registrationPersonRegistrationCompositeService")
}
}
ApplicationContext appContext = bb.createApplicationContext()
Additional information: Added the following lines to the PluginGrailsPlugin.groovy. The original service is still handling these requests
def dependsOn = ['appPersonRegistration': '1.0.20 > *']
List loadAfter = ['appPersonRegistration']
def doWithSpring = {
registrationPersonCourseRegistrationCompositeService(path.to.new.registration.TccRegistrationPersonCourseRegistrationCompositeService)
}
def doWithApplicationContext = { applicationContext ->
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL)
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getBeanFactory()
beanFactory.registerBeanDefinition("registrationPersonCourseRegistrationCompositeService", BeanDefinitionBuilder.rootBeanDefinition(TccRegistrationPersonCourseRegistrationCompositeService.class.getName()).getBeanDefinition())
}
I highly recommend you read the section of the documentation on Plugins. The reason why I recommend this is because plugins:
Do not include, or make use of resources.groovy
Provide a means through doWithSpring to effect the spring application
Following the information in the documentation you should have no issue overriding the service in the application context.
You must implement your changes to the application context using doWithSpring this is the key to solving your issues.
In this implementation, I had a utility method in a service for which I was attempting to provide an override. Problem is, the Aspect works as a proxy and must override a method that is called directly from another class. In my classRegistrationController, I was calling service processRegistration() which in turn called applyRules(). Example-only method names used. Since the service was calling its own utility, there was no opportunity for the proxy/wrapper to circumvent the call to applyRules(). Once this was discovered, I refactored the code in this fashion: Controller calls processRegistration as it always had. After returning, another call is made to the service, processLocalRules(). The new method is an empty placeholder intended to be overridden by the client's custom logic. The plugin with Aspect works now using resources.groovy. I prefer the doWithSpring as Joshua explained for this reason: my intent to get the plugin to work without modification to the original app-config; otherwise resource.groovy is a valid approach. Upvoting Joshua's answer as it does satisfy the requirement and is cleaner. Thanks!

Resources