Circular view path [error] while json output expected in springboot - spring-boot

newbie to Springboot with gradle, I am creating a restful service which queries the db2 database and returns the result in json.
The desired output
{
resource: {
results: [
{
currencyCode: "JPY",
conversionRateToUSD: "0.010286580",
conversionRateFromUSD: "97.214040040",
startDate: "2011-01-01",
endDate: "2011-01-29"
}
]
}
}
The api i am trying to build is http://localhost:8080/apis/exchange-rates/referenceDate=2015-01-01&currencyCode=JPY
I have created the below controller class
#RestController
#Slf4j
#RequestMapping("/apis")
public class IndividualExchangeRateController {
#Autowired
private IndividualExchangeRateService individualExchangeRateService;
public IndividualExchangeRateController(IndividualExchangeRateService individualExchangeRateService) {
this.individualExchangeRateService = individualExchangeRateService;
}
#RequestMapping(value = "/exchange-rates", method = RequestMethod.GET)
#ResponseStatus(HttpStatus.OK)
public #ResponseBody IndividualResource getIndividual(#RequestParam("referenceDate") #DateTimeFormat(pattern = "YYYY-MM-DD")Date referenceDate,
#RequestParam(value = "currencyCode", required = false) String currencyCode){
try {
System.out.println("Inside Controller");
return individualExchangeRateService.getIndividualExchangeRate(referenceDate, currencyCode);
}
catch (HttpClientErrorException e){
throw new InvalidRequestException(e.getMessage());
}
}
}
I am getting the below error when i call the api
javax.servlet.ServletException: Circular view path [error]: would dispatch back to the current handler URL [/error] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)
Can anybody help out on this ?
As the output is json i do not have thymeleaf dependencies on my application
Below is the gradle build file
plugins {
id 'org.springframework.boot' version '2.1.7.RELEASE'
id 'java'
}
apply plugin: 'io.spring.dependency-management'
group = 'com.abc.service'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
maven { url "http://artifactory.abcinc.dev/artifactory/maven-repos" }
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
compileOnly 'org.projectlombok:lombok:1.18.8'
annotationProcessor 'org.projectlombok:lombok:1.18.8'
runtime 'com.ibm.db2.jcc:db2jcc4:4.19.49'
compile group: 'org.springframework', name: 'spring-jdbc', version: '5.1.9.RELEASE'
compile group: 'com.zaxxer', name: 'HikariCP', version: '3.3.1'
compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.9.9'
}
public class IndividualExchangeRate {
private String currencyCode;
private double conversionRateFromUSD;
private double conversionRateToUSD;
}
public class IndividualResource {
private List<IndividualExchangeRate> individualExchangeRates;
}
All the classes are annotated with lombok.

Spring Boot uses a default Whitelabel error page in case server error.So there might be some code snippets which is breaking your appliaction flow.
Add server.error.whitelabel.enabled=false in your application.properties file .
OR add the following code snippets :
#Controller
public class AppErrorController implements ErrorController{
private static final String PATH = "/error";
#RequestMapping(value = PATH)
public String error() {
return "Error handling";
}
#Override
public String getErrorPath() {
return PATH;
}
}

Related

IntelliJ Could not set unknown property 'mainClassName' for root project 'Blue Bot' of type org.gradle.api.Project

I am following a tutorial to make a basic Discord Bot, (https://medium.com/discord-bots/making-a-basic-discord-bot-with-java-834949008c2b) and i got the error, Could not set unknown property 'mainClassName' for root project 'Blue Bot' of type org.gradle.api.Project and I don't know how to fix it. Here is my build.grade code
plugins {
id 'java'
}
mainClassName = "Main"
group 'BlueBot'
version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
jcenter()
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
compile 'net.dv8tion:JDA:4.0.0_62'
}
and here is my Main.java code
import net.dv8tion.jda.api.AccountType;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import javax.security.auth.login.LoginException;
public class Main extends ListenerAdapter {
public static void main(String[] args) throws LoginException {
JDABuilder builder = new JDABuilder(AccountType.BOT);
String token = "enter token here";
builder.setToken(token);
builder.addEventListeners(new Main());
builder.build();
}
#Override
public void onMessageReceived(MessageReceivedEvent event) {
System.out.println("We received a message from " +
event.getAuthor().getName() + ": " +
event.getMessage().getContentDisplay()
);
if (event.getMessage().getContentRaw().equals("I am lonely")) {
event.getChannel().sendMessage("Who isn't?").queue();
}
}
}
Let me know if you need more info.
You need to apply the application plugin:
plugins {
id 'application'
}

NoSuchMethodException QueryDSL with Spring Boot & Spring Data Mongo

I am trying to implement Query DSL on my Spring Boot 2.0.4.RELEASE app that uses Spring Data Mongo 2.0.4.RELEASE & Gradle 4.10.
I am using Spring Tool Suite for running it locally.
Did the following steps which I found from multiple sources including Spring data documentation:
created gradle/querydsl.gradle which has below content to generate Q classes
apply plugin: "com.ewerk.gradle.plugins.querydsl"
sourceSets {
main {
java {
srcDir "$buildDir/generated/source/apt/main"
}
}
}
querydsl {
springDataMongo = true
querydslSourcesDir = "$buildDir/generated/source/apt/main"
}
dependencies {
compile "com.querydsl:querydsl-mongodb:4.1.4"
compileOnly "com.querydsl:querydsl-apt:4.1.4"
}
sourceSets.main.java.srcDirs = ['src/main/java']
Calling above gradle file from main build.gradle as shown below
buildscript {
ext { springBootVersion = "2.0.4.RELEASE" }
repositories { mavenCentral() }
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"
classpath "gradle.plugin.com.ewerk.gradle.plugins:querydsl-plugin:1.0.9"
}
}
plugins {
id "java"
id "eclipse"
id "org.springframework.boot" version "2.0.4.RELEASE"
id "io.spring.dependency-management" version "1.0.6.RELEASE"
}
sourceCompatibility = 1.8
repositories { mavenCentral() }
dependencies {
...
compile("org.springframework.boot:spring-boot-starter-web:${springBootVersion}")
compile("org.springframework.boot:spring-boot-starter-data-mongodb:${springBootVersion}")
...
}
apply from: 'gradle/querydsl.gradle'
/* Added this because Eclipse was not able to find generated classes */
sourceSets.main.java.srcDirs = ['build/generated/source/apt/main','src/main/java']
compileJava.dependsOn processResources
processResources.dependsOn cleanResources
After this updated the Repository annotated interface as below. Note: I also use Fragment Repository FragmentOrderRepository for some custom queries.
public interface OrderRepository<D extends OrderDAO>
extends EntityRepository<D>, PagingAndSortingRepository<D, String>, FragmentOrderRepository<D>, QuerydslPredicateExecutor<D> {}
Then in controller created a GET mapping as shown here
#RestController
public class OrderController {
#GetMapping(value="/orders/dsl", produces = { "application/json" })
public ResponseEntity<List> getOrdersDSL(#QuerydslPredicate(root = OrderDAO.class) Predicate predicate, Pageable pageable, #RequestParam final MultiValueMap<String, String> parameters) {
return (ResponseEntity<List>) orderService.getTools().getRepository().findAll(predicate, pageable);
}
}
Then in my runner class I added EnableSpringDataWebSupport annotation
#SpringBootApplication
#EnableSpringDataWebSupport
public class SampleApp {
public static void main(String[] args) {
SpringApplication.run(SampleApp.class, args);
}
}
With this my app starts up without any errors but when I try hitting the path http://localhost:5057/orders/dsl?email=test#test.com
I get a NoSuchMethodException with message No primary or default constructor found for interface com.querydsl.core.types.Predicate.
Can anyone please help with some pointers to solve this issue?
It seems that parameters are not getting resolved to a type.
---- UPDATE 09/19/19 ----
While debugging I found that a class HandlerMethodArgumentResolverComposite which finds ArgumentResolver for given MethodParameter from a List of argumentResolvers(of type HandlerMethodArgumentResolver). This list does not contain QuerydslPredicateArgumentResolver. Hence it is not able to resolve the arguments.
This means QuerydslWebConfiguration which adds above resolver for Predicate type is not getting called, which in turn indicates that some AutoConfiguration is not happening.
Probably I am missing some annotation here.
Found the mistake I was doing, was missing EnableWebMvc annotation on my Configuration annotated class.
Details are in this documentation.

Spring 4 + Embedded Tomcat 7

I try to build a web app using Spring Web MVC 4.3.2 and embedded Tomcat 7.0.64.
I did not manage to write the correct main method to start embedded Tomcat. It works for Spring Controller sending #ResponseBody content (JSON) but failed for JSP views.
public static void main(String[] args) throws Exception {
String appBase = ".";// What to put here ?
Tomcat tomcat = new Tomcat();
String contextPath = "";
String port = System.getProperty("server.port");
tomcat.setPort(port == null ? 8080 : Integer.valueOf(port));
tomcat.getHost().setAppBase(appBase);
Context context = tomcat.addWebapp(contextPath, appBase);
// So that it works when in it's launched from IntelliJ or Eclipse
// Also need that a folder named "META-INF" exists in build/classes/main
// https://bz.apache.org/bugzilla/show_bug.cgi?id=52853#c19
((StandardJarScanner) context.getJarScanner()).setScanAllDirectories(true);
tomcat.start();
tomcat.getServer().await();
}
For JSP view it says : The requested resource is not available (WEB-INF/views/home.jsp) HTTP 404
If I set the appBase variable to the absolute path where the JSPs are, it works. But, of course, it is not a solution as it would not work on another machine. I need a relative path.
If I set appBase varibale to "src/main/webapp", then Tomcat fails to start with the following error : java.lang.IllegalArgumentException: Document base C:\blabla\spring-jsp-embedded-tomcat\tomcat.8080\src\main\webapp\src\main\webapp does not exist or is not a readable directory.
Morevover, the jar that is built with Gradle fat jar technique does not contain the WEB-INF dir.
How can I do to make a simple Spring MVC app working with an embedded Tomcat and JSPs (to be launched with java -cp path/to/my/jar com.app.Launcher) ?
build.gradle :
apply plugin: 'java'
sourceCompatibility = 1.7
version = '1.0'
jar {
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}
repositories {
maven { url "http://repo1.maven.org/maven2" }
}
dependencies {
compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.6.2'
compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.6.2'
compile group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: '2.6.2'
compile 'org.springframework:spring-webmvc:4.3.2.RELEASE'
compile 'com.fasterxml.jackson.core:jackson-databind:2.7.0'
compile 'javax.servlet:javax.servlet-api:3.0.1'
compile 'javax.servlet.jsp:jsp-api:2.2'
compile 'javax.servlet:jstl:1.2'
// Embedded Tomcat
// 2 mandatory libs
compile 'org.apache.tomcat.embed:tomcat-embed-core:7.0.64'
compile 'org.apache.tomcat.embed:tomcat-embed-logging-juli:7.0.64'
// To enable JSPs
compile 'org.apache.tomcat.embed:tomcat-embed-jasper:7.0.64'
testCompile group: 'junit', name: 'junit', version: '4.+'
}
Tomcat launcher :
public class Launcher {
public static void main(String[] args) throws Exception {
String contextPath = "";
// String appBase = "C:/absolute/path/to/webapp/dir"; // It works but of course I need a relative path
// String appBase = "."; // Works only for Controller sending back ResponseBody (JSON) but fail to find jsp files
String appBase = "src/main/webapp"; // Tomcat does not start properly
Tomcat tomcat = new Tomcat();
String port = System.getProperty("server.port");
tomcat.setPort(port == null ? 8080 : Integer.valueOf(port));
tomcat.getHost().setAppBase(appBase);
Context context = tomcat.addWebapp(contextPath, appBase);
// So that it works when in it's launched from IntelliJ or Eclipse
// Also need that a folder named "META-INF" exists in build/classes/main
// https://bz.apache.org/bugzilla/show_bug.cgi?id=52853#c19
((StandardJarScanner) context.getJarScanner()).setScanAllDirectories(true);
tomcat.start();
tomcat.getServer().await();
}
}
Spring web app initializer :
public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { RootConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { WebConfig.class };
}
}
WebConfig :
#Configuration
#EnableWebMvc
#ComponentScan("com.app")
public class WebConfig extends WebMvcConfigurerAdapter {
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setExposeContextBeansAsAttributes(true);
return resolver;
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
Folder structure :
Apparently, embedded Tomcat expects static resources to be in a META-INF/resources directory. I followed this : tutorial and I checked how the final jar was structured.
So I modified the Gradle build script to put the JSPs there.
sourceSets {
main {
resources.srcDirs = ["src/main/webapp"]
output.resourcesDir = "$buildDir/classes/main/META-INF/resources"
}
}
And now it works. However, I have the feeling that it's a makeshift job. If someone has a more satisfying and educational answer, I would be pleased to get it.

spring boot 1.4, spock and application.properties

I am trying to write some tests for my Spring Boot 1.4.0 with Spock and my application-test-properties file is not being picked up.
I have this in my gradle:
dependencies {
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.springframework.boot:spring-boot-starter-security')
compile('org.springframework.boot:spring-boot-starter-web')
compile 'org.codehaus.groovy:groovy-all:2.4.1'
testCompile('org.springframework.boot:spring-boot-starter-test')
testCompile('org.spockframework:spock-spring:1.0-groovy-2.4') {
}
Then I have this in
/src/test/groovy/resources:
# JWT Key
jwt.key=MyKy#99
And finally my Spock test:
#SpringBootTest(classes = MyApplication.class, webEnvironment=SpringBootTest.WebEnvironment.RANDOM_PORT)
#TestPropertySource("application-test.properties")
public class TokenUtilityTest extends Specification {
#Autowired
private TokenUtility tokenUtility
def "test a valid token creation"() {
def userDetails = new User(username: "test", password: "password", accountNonExpired: true, accountNonLocked: true,
);
when:
def token = tokenUtility.buildToken(userDetails)
then:
token != null
}
}
Which is testing this class:
#Component
public class TokenUtility {
private static final Logger LOG = LoggerFactory.getLogger( TokenUtility.class );
#Value("${jwt.key}")
private String jwtKey;
public String buildToken(UserDetails user) {
return Jwts.builder()
.setSubject(user.getUsername())
.signWith(SignatureAlgorithm.HS512, jwtKey)
.compact();
}
public boolean validate(String token) {
try {
Jwts.parser().setSigningKey(jwtKey).parseClaimsJws(token);
return true;
} catch (SignatureException e) {
LOG.error("Invalid JWT found: " + token);
}
return false;
}
}
I originally instantiated the TokenUtility on my test but the application-test.properties was never loaded (I am assuming since jwtKey was null). So I am trying #Autowired my class under test, but now that is null.
It looks like Spring Boot 1.4 changed a lot for testing, so perhaps I am not wiring this up correctly?
There are several things wrong with your test code; first, your dependencies are bad - Spock 1.0 does not support #SpringBootTest annotation so no context will be initialized and no post-processing will be done, hence the null pointer exception: nothing will be autowired.
Support for that annotation was added in Spock 1.1, which is still release-candidate, so you'll have to use that:
dependencies {
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.springframework.boot:spring-boot-starter-security')
compile('org.springframework.boot:spring-boot-starter-web')
compile group: 'io.jsonwebtoken', name: 'jjwt', version: '0.6.0'
compile('org.codehaus.groovy:groovy')
testCompile('org.springframework.boot:spring-boot-starter-test')
testCompile('org.spockframework:spock-core:1.1-groovy-2.4-rc-1')
testCompile('org.spockframework:spock-spring:1.1-groovy-2.4-rc-1')
testCompile group: 'com.h2database', name: 'h2', version: '1.4.192'
}
Then, your path to the application-test.properties is wrong and should be /application-test.properties since it is in the root of the classpath:
#SpringBootTest(classes = DemoApplication.class,
webEnvironment = WebEnvironment.RANDOM_PORT)
#TestPropertySource("/application-test.properties")
public class TokenUtilityTest extends Specification {
#Autowired
TokenUtility tokenUtility
def "test a valid token creation"() {
def userDetails = new User("test", "password", Collections.emptyList());
when:
def token = tokenUtility.buildToken(userDetails)
then:
token != null
}
}
I had the similar problem, but for me, the solution was to change double quotes ".." to single quotes '..' inside the #Value annotation when working with Spock. Please find the example below:
#Value('${jwt.key}')
private String jwtKey;
PS - This is not the exact answer to the question. I am posting this for someone who faces a similar problem like mine and ends up here.

Error 406 on Spring 3+Google App Engine on Android Studio

I am using Google App Engine to develop a backend module provided by Android Studio. I am also using Spring 3 to map URL to class.Although,I have successfully used the combo on Eclipse.But on Android Studio getting a peculiar error(May be because of gradle error).Consider the following files-
build.gradle
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.google.appengine:gradle-appengine-plugin:1.9.18'
}
}
repositories {
jcenter();
}
apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'appengine'
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
dependencies {
appengineSdk 'com.google.appengine:appengine-java-sdk:1.9.18'
compile 'javax.servlet:servlet-api:2.5'
compile 'org.springframework:spring-webmvc:4.0.0.RELEASE'
compile 'com.google.code.gson:gson:2.5'
}
appengine {
downloadSdk = true
appcfg {
oauth2 = true
}
}
MyServlet.java . When I am accessing conventional MyServlet the Gson get successfully loaded and returns the required JSON.
public class MyServlet extends HttpServlet {
#Override
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("application/json");
Gson gson = new Gson();
Shop sh = new Shop();
sh.setName("Gufran Kurshid");
sh.setAddress("Pitampura new Delhi");
sh.setId(5235);
resp.getWriter().println(gson.toJson(sh));
}
}
MyController.java - A normal controller URL /hello is also easily accessible.But /getDummyJSON which is made to return JSON is giving Error 406.
#Controller
#RequestMapping("/greet")
public class MyController {
#RequestMapping("/hello")
public ModelAndView helloDost() {
ModelAndView modelAndView = new ModelAndView("rat");
modelAndView.addObject("message", "Hello Dost");
return modelAndView;
}
#RequestMapping(value = "/getDummyJSON", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET)
public
#ResponseBody
Map getDummyJSON() {
Map map = new HashMap<String, Object>();
map.put("status", true);
map.put("message", "Hello Friends");
return map;
}
}
My study says the Spring is not able map and load Gson classes.Is there any thing wrong with Android Studio or my Gradle file ?

Resources