I am trying to build Spring-boot CRUD application with Hibernate and REST -API.However when I try to run the app everything is working fine but console is displaying the following error
java.lang.NullPointerException: null
at io.javabrains.EmployerController.getAllEmployers(EmployerController.java:20) ~[classes/:na]
I tried to change the value however it didnt work
EmployerService.java
package io.javabrains;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Service;
import io.javabrains.Entity.Employer;
#Service
public class EmployerService {
private Repository repository;
public List<Employer>getAllEmployers(){
List<Employer>employers = new ArrayList<>();
repository.findAll()
.forEach(employers::add);
return employers;
}
public void addEmployer(Employer employer) {
repository.save(employer);
}
}
EmployerController.java
package io.javabrains;
import java.util.List;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import io.javabrains.Entity.Employer;
#RestController
public class EmployerController {
private EmployerService service;
#RequestMapping("/employer")
public List<Employer>getAllEmployers()
{
return service.getAllEmployers();
}
/*
* #RequestMapping("/employer/{id}") public Employer getEmployer(#PathVariable
* int id) { return service.getEmployer(id); }
*/
#RequestMapping(method=RequestMethod.POST,value="/employer/create")
public void addEmployer(#RequestBody Employer employer) {
service.addEmployer(employer);
}
}
....
On the analysis of the code snippet given, the null pointer exception occurred since your code doesn't ask the spring dependency injector to inject EmployerService as a dependency to EmployerController, so it doesn't inject the EmployerService bean class to the reference private EmployerService employerService; thus it is null in EmployerController. You can ask Spring Dependency Injector to inject dependency by adding #Autowire annotation private EmployerService service; refence in EmployerController
Update your EmployerService to the following will work
package io.javabrains;
import java.util.List;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import io.javabrains.Entity.Employer;
#RestController
public class EmployerController {
//UPDATE : Autowiring
#Autowired
private EmployerService employerService;
#RequestMapping("/employer")
public List < Employer > getAllEmployers() {
return service.getAllEmployers();
}
/*
* #RequestMapping("/employer/{id}") public Employer getEmployer(#PathVariable
* int id) { return employerService.getEmployer(id); }
*/
#RequestMapping(method = RequestMethod.POST, value = "/employer/create")
public void addEmployer(#RequestBody Employer employer) {
employerService.addEmployer(employer);
}
}
And Also, the same issue would occur in Service when trying to access repository.
Update EmployeeService.java code include #autorwired logic:
package io.javabrains;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import io.javabrains.Entity.Employer;
#Service
public class EmployerService {
#Autowired
private Repository repository;
public List<Employer>getAllEmployers(){
List<Employer>employers = new ArrayList<>();
repository.findAll()
.forEach(employers::add);
return employers;
}
public void addEmployer(Employer employer) {
repository.save(employer);
}
}
private EmployerService employerService;
This mean you have created a reference variable of EmployerService not an object of EmployerService. Which can be done by using a new keyword. But as you know Spring Container uses DI(Dependency Injection) to manage a beans(an object, in above case object of EmployerService). So the object instantiation and whole lifecycle of an object is managed by the spring. For this we have to tell that the this object should be managed by the spring which is done by using #Autowired annotation.
You need to get object of repository before using, for that add #Autowired on
private Repository repository;
in your EmployerService class.
#Autowired is definitely the solution.
But your service class, if you ask for your REPOSITORY, you should put there too.
So in my problem, the solution was
#Autowired
private ProductService productService;
And
#Autowired
ProductRepository productRepository;
there was a line inside a method that was throwing this NullpointerException then later on I put that line in the if statement and it worked for me seamlessly.
example:
if (user != null) { application.setEmailaddress(user.getEmail());}
Related
i am using keycloak and spring to get the user list in a rest service, however the rest return the html instead of json data.
here is the service.
import org.keycloak.representations.idm.UserRepresentation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
#Service
public class UserServiceImpl implements UserService{
#Autowired
KeycloakInstance keycloakInstance;
public List<UserRepresentation> loadUsers(String realm) {
return keycloakInstance.getInstance()
.realm(realm)
.users()
.list();
}
}
here is the controller.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.keycloak.representations.idm.UserRepresentation;
import java.util.List;
#RestController
#RequestMapping("/api/admin/users")
public class UserController {
#Autowired
private UserService userService;
#GetMapping(value = "", produces="application/json")
public List<UserRepresentation> loadUsers() {
String realm = "abc";
return userService.loadUsers(realm);
}
}
any idea how to fix this?
You would need to add the path to #GetMapping, this should work
#ResponseBody
#GetMapping(value = "/api/admin/users", produces="application/json")
public List<UserRepresentation> loadUsers() {
String realm = "abc";
return userService.loadUsers(realm);
}
or using this way
#GetMapping (value = "/api/admin/users", produces = MediaType.APPLICATION_JSON_VALUE)
As #ConstantinKonstantinidis commented, add to RequestMapping produces JSON to apply to your method (and all methods):
#RequestMapping(value = "/api/admin/users", produces = MediaType.APPLICATION_JSON_VALUE
Supported at the type level as well as at the method level
Another option is to add the path to #GetMapping ,e.g.
#RequestMapping("/api/admin")
public class UserController {
#GetMapping(value = "/users", produces="application/json")
I am totally new to Cassandra, this is the very first time, never used it before, so far we have been using Spring Boot and MySql as our DB, but now we are planning to migrate our database to Cassandra with the minimum code or no change.
here is a sample demo of code that we have been using.
config class
package com.example.demo.config;
import com.zaxxer.hikari.HikariDataSource;
import lombok.Generated;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.util.HashMap;
import static org.hibernate.cfg.AvailableSettings.*;
#Configuration
#EnableTransactionManagement
#EnableJpaAuditing
#EnableJpaRepositories(entityManagerFactoryRef = "orclEntityManagerFactory", transactionManagerRef = "orclTransactionManager", basePackages = {"com.example.demo.repository"})
#Generated
public class DataSourceConfig {
#Value("${spring.datasource.driver-class-name}")
private String orclDbDriver;
#Value("${spring.datasource.url}")
private String orclDbConnUrl;
#Value("${spring.datasource.username}")
private String orclDbUsername;
#Value("${spring.datasource.password}")
private String orclDbPassword;
#Value("${spring.datasource.poolName}")
private String dataSourcePoolName;
#Value("${spring.jpa.properties.hibernate.dialect}")
private String orclHibernateDialect;
#Value("${spring.jpa.hibernate.ddl-auto}")
private String hibernateDDL;
#Value("${spring.jpa.show-sql}")
private boolean showSql;
#Value("${spring.datasource.packagesToScan}")
private String[] packagesToScan;
public DataSourceConfig() {
}
#Bean
#Primary
public DataSource orclDataSource() {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setDriverClassName(this.orclDbDriver);
dataSource.setJdbcUrl(this.orclDbConnUrl);
dataSource.setUsername(this.orclDbUsername);
dataSource.setPassword(this.orclDbPassword);
dataSource.setPoolName(this.dataSourcePoolName);
return dataSource;
}
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean orclEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setDataSource(this.orclDataSource());
factory.setPackagesToScan(this.packagesToScan);
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
jpaVendorAdapter.setDatabase(Database.MYSQL);
jpaVendorAdapter.setGenerateDdl(Boolean.TRUE);
jpaVendorAdapter.setShowSql(showSql);
jpaVendorAdapter.setDatabasePlatform(orclHibernateDialect);
factory.setJpaVendorAdapter(jpaVendorAdapter);
HashMap<String, Object> properties = new HashMap();
properties.put(HBM2DDL_AUTO, this.hibernateDDL);
properties.put(DIALECT, this.orclHibernateDialect);
properties.put(STATEMENT_BATCH_SIZE, "500");
properties.put(ORDER_UPDATES, "true");
properties.put(ORDER_INSERTS, "true");
properties.put(GENERATE_STATISTICS, "true");
factory.setJpaPropertyMap(properties);
return factory;
}
#Bean
#Primary
public JpaTransactionManager orclTransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(this.orclEntityManagerFactory().getObject());
return transactionManager;
}
}
controller class
import com.example.demo.entity.Child;
import com.example.demo.repository.ChildRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.sql.Timestamp;
import java.util.List;
#RestController
public class HelloController {
#Autowired
private ChildRepository childRepository;
#GetMapping("put")
public Child getHello() {
Child child = new Child();
child.setName("shrikant");
child.setUpdatedAt(new Timestamp(System.currentTimeMillis()));
return childRepository.save(child);
}
#GetMapping("get")
public List<Child> hello() {
return childRepository.findAll();
}
}
repository
package com.example.demo.repository;
import com.example.demo.entity.Child;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface ChildRepository extends JpaRepository<Child, Long> {
}
application.dev
spring.datasource.url=jdbc:mysql://localhost:3306/student_db?jdbcCompliantTruncation=false&sessionVariables=sql_mode='NO_ENGINE_SUBSTITUTION'&useSSL=false&useServerPrepStmts=false&rewriteBatchedStatements=true&useUnicode=true&characterEncoding=utf8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.poolName=springHikariCp
spring.jpa.generate-ddl=true
spring.jpa.database.schema=student_db
spring.jpa.hibernate.ddl-auto=update
#spring.jpa.hibernate.ddl-auto=none
spring.jpa.show-sql=true
spring.datasource.packagesToScan=com.example.demo.entity
spring.profiles.active=dev
build.gradle
plugins {
id 'org.springframework.boot' version '2.2.6.RELEASE'
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '8'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
compile 'mysql:mysql-connector-java'
annotationProcessor 'org.projectlombok:lombok'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
test {
useJUnitPlatform()
}
I have installed Cassandra with the help of google and able to login using cqlsh.
created keyspace
CREATE KEYSPACE IF NOT EXISTS mykeyspace WITH replication = {'class':'SimpleStrategy', 'replication_factor':1};
added Cassandra dependency in Gradle
compile 'org.springframework.boot:spring-boot-starter-data-cassandra'
but what should be the configuration properties in the application.properties, I couldn't find any of the examples on Google creating a custom data source, all are using Spring Boot auto-config, but I can't do that, because that will be a major code change.
You need to use the CassandraRepository instead of JpaRepository interface
public interface ChildRepository extends CassandraRepository<Child, Long> { }
You need to have these properties in your application.properties
spring.data.cassandra.contact-points=127.0.0.1 (or your corresponding connection uri)
spring.data.cassandra.username=<username, if any>
spring.data.cassandra.password=<password, if any>
spring.data.cassandra.keyspace=default
spring.data.cassandra.port=9042
spring.data.cassandra.schema-action=NONE
Then you will be relatively fine. But like the other guys said in the comments section, it is quite important that you should understand the nature of Cassandra. If you don't implement your data model based on your queries, it won't be successful.
I have an issue serializing a spring managed bean.
I want to return an autowired bean as the response for a restcontroller. I have read several responses, one of which advises using a simpleFilter.(Use SimpleFilter to exclude non required fields.). However I do not think this suggestion is very practical, and moreover, I am sure there is a much more simple and concrete way to solve the problem.
I have a spring managed bean called JobStatus.
#Component
#Scope(value="Prototype")
public class JobStatus{
private Integer job_type;
public Integer getJob_type() {
return job_type;
}
public void setJob_type(Integer job_type) {
this.job_type = job_type;
}
public JobStatus(){
}
}
I have a controller as follows:
#RestController
public class JobController {
#Autowired
JobStatus js;
#RequestMapping(value = "/get_job_status", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody
JobStatus get_job_status(#RequestBody JobStatusRequest req) {
js.setJobType(req.getJobType);
ObjectMapper mapper = new ObjectMapper();
try {
System.out.println(mapper.writeValueAsString(js));
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return js;
}
}
It throws the following exception:
com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class org.springframework.cglib.proxy.NoOp$1 and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: ATM.Job.JobStatus$$EnhancerBySpringCGLIB$$be675215["callbacks"])
I have tried changing the scope of JobStatus to "singleton" and "session" and "request" and it doesn't make any difference. How are we supposed to serialize "proxies"?
You can just tell Jackson: "serialize my class using the very same type as supertype". Since Spring proxies subclass your original class, this seem to work at least on Spring Boot 2.0.4.RELEASE:
#JsonSerialize(as=MyCompontClass.class)
#Component
public class MyCompontClass{
// fields, getters, setters
}
Jackson API docs say:
as
public abstract Class as
Supertype (of declared type, which itself is supertype of runtime
type) to use as type when locating serializer to use.
Create a view class
public class JobStatusView {
public JobStatusView(JobStatus js) {
job_type = js.getJob_type();
}
private Integer job_type;
public Integer getJob_type() {
return job_type;
}
public void setJob_type(Integer job_type) {
this.job_type = job_type;
}
}
Have your controller method return new JobStatusView(js) or create a Factory class or whatever your preferred method for creating instances is.
This has the benefit of separating the data from the view. You can add whichever Jackson annotations on the view class later, if the need arises, without having to pile them into the original bean.
I am not sure if this will work but it worked for me in another context.
You can try using #Configurable on your Jobstatus class(with AspectJ weaving configured) and create a new instance of job status in the controller. Spring would inject the bean whenever JObStatus's new instance is called. You can then serialize the jobstatus object as usual.
If it is acceptable for you to only have fields reachable via public getter method getting serialised, you can configure Jackson to ignore the non-public fields. This results in the proxy fields not being serialised:
add a #Configuration bean somewhere on your class path in a package under where the Application.java class for spring resides:
in there set ObjectMapper properties
objectMapper.setVisibility(PropertyAccessor.ALL,
JsonAutoDetect.Visibility.NONE);
objectMapper.setVisibility(PropertyAccessor.GETTER,
JsonAutoDetect.Visibility.PUBLIC_ONLY);
Here is a complete class:
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import
org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import
org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
#Configuration
public class JacksonConfig extends WebMvcConfigurerAdapter {
#Bean
#Primary
public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
setup(objectMapper);
return objectMapper;
}
public void setup(ObjectMapper objectMapper) {
objectMapper.setVisibility(PropertyAccessor.ALL,
JsonAutoDetect.Visibility.NONE);
objectMapper.setVisibility(PropertyAccessor.GETTER,
JsonAutoDetect.Visibility.PUBLIC_ONLY);
}
#Override
public void configureMessageConverters(
List<HttpMessageConverter<?>> converters) {
final MappingJackson2HttpMessageConverter converter =
getMappingJackson2HttpMessageConverter();
converters.add(converter);
super.configureMessageConverters(converters);
}
#Bean
#Primary
public MappingJackson2HttpMessageConverter
getMappingJackson2HttpMessageConverter() {
final MappingJackson2HttpMessageConverter converter = new
MappingJackson2HttpMessageConverter();
final ObjectMapper objectMapper = new ObjectMapper();
setup(objectMapper);
converter.setObjectMapper(objectMapper);
converter.setPrettyPrint(true);
return converter;
}
}
I'm trying to use the primefaces LazyDataModel for a tabelaric view in JSF, the problem is that I'm unable to inject anything into the class. I always get null fot the injected object.
For example I'm injecting
#PersistenceContext(unitName = "domainDS")
private EntityManager em;
or an EJB
#EJB
OrganizationHandler orgHandler;
but I get null for both of them.
The whole lazy datamodel class
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.primefaces.model.LazyDataModel;
import org.primefaces.model.SortOrder;
import si.arctur.controller.OrganizationHandler;
import si.arctur.model.Organization;
#Named
#Stateless
public class LazyOrganizationDataModel extends LazyDataModel<Organization> implements Serializable {
private static final long serialVersionUID = 675394666656356734L;
#PersistenceContext(unitName = "domainDS")
private EntityManager em;
#EJB
OrganizationHandler orgHandler;
public LazyOrganizationDataModel() {
super();
}
#SuppressWarnings("unchecked")
#Override
public List<Organization> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String,String> filters) {
List<Organization> data = orgHandler.selectOrganizatoins(first, pageSize, sortField, "asc", filters);
//row count
this.setRowCount(data.size());
return data;
}
}
You're probably not injecting the lazy data model. Based on their examples, they show someone instantiating it. You should instead get a reference via CDI to the bean.
I want to use parameterized JUnit tests on a play! framework (1.2.5) application.
This is my very simple test example:
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import play.test.FunctionalTest;
#RunWith(Parameterized.class)
public class ParameterizedExampleTest extends FunctionalTest {
private int i;
#Parameters
public static List<Object[]> parameters() {
return Arrays.asList(new Object[][] {{1},{2},{3}});
}
public ParameterizedExampleTest(int i) {
this.i = i;
}
#Test
public void someTest() {
System.out.println("i is " + i);
}
}
When I run the test, I get an IllegalArgumentException telling me "Test class can only have one constructor". I perfectly agree with that as FunctionalTest extends BaseTest which has a #RunWith(PlayJUnitRunner.class) annotation and the PlayJUnitRunner has a constructor.
Any help welcome!
I found a rather nice solution:
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
import play.test.FunctionalTest;
#RunWith(Parameterized.class)
public class ParameterizedExampleTest extends FunctionalTest {
#Parameter(0)
public int i;
#Parameters
public static List<Object[]> parameters() {
return Arrays.asList(new Object[][] {{1},{2},{3}});
}
#Test
public void someTest() {
System.out.println("i is " + i);
}
}
You have to mark the parameters with the #Parameter(...) Annotation and the number of the parameter in the parameters array. No constructor is needed hence it runs smoothly with play.
Drawback: You will need JUnit 4.11 as this feature is not implemented in 4.10 which is what play (1.2.5) comes with.