How do I enable automatic JSON marshalling in Jersey using autodiscovery? - java

I'm trying to create a very simple example rest service that produces JSON. My understanding is that Jersey should auto discover the Jackson libraries (if they're on the classpath) and the JSON marshalling should happen automatically.
The following error is reported when I call GET. Am I using the appropriate dependencies for this to work or am I missing something more fundamental?
SEVERE: MessageBodyWriter not found for media type=application/json, type=class jsonex.Person, genericType=class jsonex.Person.
Dependencies
I'm using Gradle with the gretty plugin applied and these dependencies:
dependencies {
compile group: 'javax.ws.rs', name: 'javax.ws.rs-api', version: '2+'
runtime group: 'org.glassfish.jersey.containers', name: 'jersey-container-servlet', version: '2.23'
runtime group: 'org.glassfish.jersey.media', name: 'jersey-media-json-jackson', version: '2.7'
}
Application class
package jsonex;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import java.util.Collections;
import java.util.Set;
#ApplicationPath ("services")
public class PersonApp extends Application {
#Override
public Set<Object> getSingletons() {
return Collections.singleton(new PersonService());
}
}
Service class
package jsonex;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
#Path("people")
public class PersonService {
#GET
#Produces(MediaType.APPLICATION_JSON)
public Person getPerson() {
Person me = new Person();
me.setFirstName("Dave");
me.setLastName("R");
return me;
}
}
POJO
package jsonex;
public class Person {
String firstName, lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
Thanks!

In order to consume/produce JSON in Jersey with Jackson you must register the Jackson feature (JacksonFeature) in your application. It's not auto discoverable as some other Jersey features.
After adding the jersey-media-json-jackson module to your dependencies, register the JacksonFeature in your Application / ResourceConfig subclass:
#ApplicationPath("/api")
public class MyApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<Class<?>>();
classes.add(JacksonFeature.class);
return classes;
}
}
#ApplicationPath("/api")
public class MyApplication extends ResourceConfig {
public MyApplication() {
register(JacksonFeature.class);
}
}
The steps to use Jackson as a JSON provider for Jersey are fully described in this answer. For more details, also check the Jersey documentation.

Related

#Autowired class from service cannot be resolved to a type in controller class

I am very new to spring boot and I cant for the life of my figure out why my #Autowired FarmService class from service cannot be resolved to a type in controller class. My application class is a package level above the service and controller class.
This is the hierarchy of the packages
FarmApplication.java code:
package prac.farm;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
#SpringBootApplication
#ComponentScan
public class FarmApplication {
public static void main(String[] args) {
SpringApplication.run(FarmApplication.class, args);
}
}
FarmController.java code:
package prac.farm.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class FarmController {
#Autowired
private FarmService farmservice;
#RequestMapping(value = "/home", method = RequestMethod.GET)
public String display() {
return farmservice.getOwner();
}
}
FarmService.java code:
package prac.farm.service;
import org.springframework.stereotype.Service;
#Service
public class FarmService {
private String owner;
private String location;
private int yearsOwned;
public FarmService() {
super();
this.owner = "alale";
this.location = "Uppsa";
this.yearsOwned = 2;
}
// public FarmService(String owner, String location, int yearsOwned) {
// super();
// this.owner = owner;
// this.location = location;
// this.yearsOwned = yearsOwned;
// }
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public int getYearsOwned() {
return yearsOwned;
}
public void setYearsOwned(int yearsOwned) {
this.yearsOwned = yearsOwned;
}
}
First of all, #ComponentScan is redundant as #SpringBootApplication already includes this annotation. Secondly, you don't seem to import the FarmService class in your controller.
So I think your confusion comes from the gap between what you've heard about Spring as a dependency injection framework and your compiler giving you this error.
The key thing about Spring is that it only acts on runtime. If you really think about what the compiler is telling you, it makes a lot of sense. You have this class called FarmService that you haven't imported, so from the point of view of the compiler, FarmController knows nothing about what a FarmService is and what methods it has.
So if you need to put the import statement, doesn't that just add it as a dependency and defeat the whole point of using spring in the first place, when we're trying to loosen the coupling? The solution is an interface.
Create an interface called FarmService and use that in your controller class. Then rename your current class FarmServiceImpl that implements that interface. You do not need to import the implementation. When Spring runs, it will autowire the implementation. In this way, you have no explicit dependency on the implementation in your code but it will still be used during runtime.

Interceptor not being called on Payara 5.184

I am running a simple Maven Java EE web project on Payara
I am trying demonstrate the working of Interceptor but it isn't getting called. I have even defined it in a beans.xml file
Payara Version: 5.184
Edition: Full
JDK Version: 1.8, Java EE 7
Operating System: Mac
Database: Oracle
Bean class
package com.maven.web;
import com.interceptors.LogNameInterceptor;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.Stateless;
import javax.faces.bean.ManagedBean;
import javax.interceptor.Interceptors;
#ManagedBean
#Stateless
public class UserBean implements User {
private String firstName;
private String lastName;
public static final Logger LOGGER = Logger.getLogger(UserBean.class.getName());
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
#Override
#Interceptors(LogNameInterceptor.class)
public String show(String fn, String ln) {
LOGGER.log(Level.INFO, "Inside method");
return "result";
}
}
User.java
package com.maven.web;
import javax.ejb.Remote;
#Remote
public interface User {
public String show(String a, String b);
}
Interceptor class
package com.interceptors;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
#Interceptor
public class LogNameInterceptor {
public static final Logger LOGGER = Logger.getLogger(LogNameInterceptor.class.getName());
#AroundInvoke
public Object aroundInvoke(InvocationContext ctx) throws Exception {
LOGGER.log(Level.INFO, "Inside Interceptor");
System.out.println(ctx.getMethod());
return ctx.proceed();
}
}
beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
<interceptors>
<class>com.interceptors.LogNameInterceptor</class>
</interceptors>
</beans>
Only 'Inside method' is printed in the log, meaning it doesn't reach the aroundInvoke method
Thanks a lot!

Parameter 0 of constructor in Class B required a bean of type Class A that could not be found

Am making an API authentication feature with JWT in Spring boot rest, but am facing the following error :
Description:
Parameter 0 of constructor in
com.icfer.huxy.icfer.controller.UserController required a bean of type
'com.icfer.huxy.icfer.service.ApplicationUserRepository' that could
not be found.
Action:
Consider defining a bean of type
'com.icfer.huxy.icfer.service.ApplicationUserRepository' in your
configuration.
Below is what I have implemented regarding ApplicationUserRepository, and UserController classes.
ApplicationUserRepository.java
import com.icfer.huxy.icfer.model.ApplicationUser;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Component;
public interface ApplicationUserRepository extends JpaRepository<ApplicationUser, Long> {
ApplicationUser findByUsername(String username);
}
ApplicationUser.java
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
#Entity
public class ApplicationUser {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String username;
private String password;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
UserController.java
import com.icfer.huxy.icfer.model.ApplicationUser;
import com.icfer.huxy.icfer.service.ApplicationUserRepository;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping("/users")
public class UserController {
private ApplicationUserRepository applicationUserRepository;
private BCryptPasswordEncoder bCryptPasswordEncoder;
public UserController(ApplicationUserRepository applicationUserRepository,
BCryptPasswordEncoder bCryptPasswordEncoder) {
this.applicationUserRepository = applicationUserRepository;
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
}
#PostMapping("/sign-up")
public void signUp(#RequestBody ApplicationUser user) {
user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
applicationUserRepository.save(user);
}
}
My gradle file de is as below :
dependencies {
implementation('org.springframework.boot:spring-boot-starter-data-jpa')
implementation('org.springframework.boot:spring-boot-starter-security')
implementation('org.springframework.boot:spring-boot-starter-web')
compile("com.auth0:java-jwt:3.4.0")
runtimeOnly('mysql:mysql-connector-java')
testImplementation('org.springframework.boot:spring-boot-starter-test')
testImplementation('org.springframework.security:spring-security-test')
}
Below is the link to my project:
Github link
One more reason sharing an actual sample is helpful as none of the code you've shared provides the information that we need to help you.
On your #SpringBootApplication you have the following:
#SpringBootApplication
#EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class, WebMvcAutoConfiguration.class})
public class IcferApplication { ... }
Because you are excluding DataSourceAutoConfiguration, no DataSource is created. There is no DataSource so JPA does not kick in. JPA is not started so your JPA repository is not created.
You could have ran your app in debug mode (i.e. by adding a -Ddebug system property):
JpaRepositoriesAutoConfiguration:
Did not match:
- #ConditionalOnBean (types: javax.sql.DataSource; SearchStrategy: all) did not find any beans of type javax.sql.DataSource (OnBeanCondition)
Matched:
- #ConditionalOnClass found required class 'org.springframework.data.jpa.repository.JpaRepository' (OnClassCondition)
- #ConditionalOnProperty (spring.data.jpa.repositories.enabled=true) matched (OnPropertyCondition)
Also, please don't use EnableAutoConfiguration together with SpringBootApplication, there is an exclude attribute on the latter as well.
Once I removed the exclude on DataSourceAutoConfiguration that error went away.

mongoTemplate bean could not be found

I am building a very simple Spring boot app with mvc + mongodb. I used Spring initializer to create the proj with web, thymeleaf and mongo dependencies. I have one controller, one model and a view but I keep on getting an error when trying to execute the app:
Description:
Field repo in com.example.CustomerController required a bean named 'mongoTemplate' that could not be found.
Action:
Consider defining a bean named 'mongoTemplate' in your configuration.
CustomerController:
import model.Customer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* Created by Hello on 25/04/2017.
*/
#Controller
#RequestMapping("/home")
public class CustomerController {
#Autowired
CustomerMongoRepo repo;
#RequestMapping(value = "/home", method= RequestMethod.GET)
public String viewingHome(Model model){
//initDB();
model.addAttribute("key", "THIS IS FROM THE MODEL");
return "homepage";
}
}
CustomerMongoRepo:
import org.springframework.data.repository.CrudRepository;
import model.Customer;
public interface CustomerMongoRepo extends CrudRepository {}
MainApp:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
#SpringBootApplication(exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class})
public class DemoApplication extends WebMvcAutoConfiguration {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Customer Model:
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
/**
* Created by Hello on 25/04/2017.
*/
#Document(collection = "customerCollection")
public class Customer {
#Id
private int id;
private String fName;
private String sName;
public Customer(){}
public Customer(int id, String fName, String sName){
setfName(fName);
setsName(sName);
setId(id);
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getfName() {
return fName;
}
public void setfName(String fName) {
this.fName = fName;
}
public String getsName() {
return sName;
}
public void setsName(String sName) {
this.sName = sName;
}
}
My Application Properties:
spring.data.mongodb.database=customer
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.uri=mongodb://localhost:27018/mydb
spring.data.mongo.repositories.enabled=true
You are excluding Mongo Configuration.
#SpringBootApplication(exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class})
Then how will spring create mongoTemplate for you. Remove this exclusion or create MongoTemplate manually and register it with application context(using #Bean)
I recently ran into this same problem and my solution was to remove spring-data-mongodb:
<!--<dependency>-->
<!-- <groupId>org.springframework.data</groupId>-->
<!-- <artifactId>spring-data-mongodb</artifactId>-->
<!-- <version>3.2.1</version>-->
<!--</dependency>-->
and I kept spring-boot-starter-data-mongodb:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
It is seen that either the two together gave conflict or I need to add 'something' that I did not know.
Happy code !!! And I hope to be of help to you
Update
Later I found something related to what could be described by the problem although I would never finish checking it:
https://stackoverflow.com/a/12389842/7911776

Spring Boot MVC mapping

I have problem with my Spring project. I just started with Spring Boot and i try to make ez controller which redirect me to another web.
When i started my application and go to browser on
localhost:8080/person
there is problem with mapping idk why
enter image description here
This is my structure
enter image description here
PersonController
package Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import Model.Person;
public class PersonController {
#RequestMapping("/person")
public String person(Model model)
{
Person p = new Person();
p.setFirstName("John");
p.setLastName("BonJovi");
p.setAge(23);
model.addAttribute("person", p);
return "personview";
}
}
Person Class
package Model;
public class Person {
String firstName;
String lastName;
int age;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
And "Main"
package demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
#Configuration
#EnableAutoConfiguration
#ComponentScan({"demo","controller"})
public class EducationProjectApplication {
public static void main(String[] args) {
SpringApplication.run(EducationProjectApplication.class, args);
}
}
Add a #Controller to the top of your PersonController
Also - just check, your #ComponentScan({"demo","controller"})
"controller" is not capitalized, but your package is declared "Controller"
You must annotated your PersonController class as #RestController.
Like Rafael said you need to put annotations above PersonController class. #RestController if you want to build a REST controller, #Controller if you want to build normal website. Make sure you already configure your view resolver so it will return a jsp files.

Categories