Spring Boot Google App Engine security annotation? - spring-boot

I'm currently working on a Spring Boot project with Google App Engine & I'm trying to check if my user is logged in on my controller actions thanks to annotations, like #PreAuthorize(isAuthenticated()). This annotation would return a HTTP 403 error if false.
Currently, my users are logged in with the Google App Engine basic UserService & I already tried to use this annotation without success (it does nothing).
Here is my pom file :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.1.3.RELEASE</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.1.3.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud</artifactId>
<version>0.47.0-alpha</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.3.1-2</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>materializecss</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.google.appengine</groupId>
<artifactId>appengine-api-1.0-sdk</artifactId>
<version>1.9.71</version>
</dependency>
I'm trying to make my code more readable currently I'm doing this on my controller :
private UserService userService = UserServiceFactory.getUserService();
#GetMapping("/pizza/create")
public String createPizza(Model model) {
if (!userService.isUserLoggedIn()) { // used in every actions that need an authentication check
return "error";
}
model.addAttribute("pizza", new Pizza());
return "create";
}
But I'd like to have this :
#PreAuthorize(isAuthenticated())
#GetMapping("/pizza/create")
public String createPizza(Model model) {
model.addAttribute("pizza", new Pizza());
return "create";
}

Related

How to setup Swagger with Spring Boot Camel for REST messaging

I'm following Swagger Java example, but can't make it work with Spring Boot Camel.
I'm running Spring Boot Camel 3.4.0, and have next dependencies in pom.xml:
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- Camel -->
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-stream-starter</artifactId>
</dependency>
<!-- REST -->
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-rest-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-servlet-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-jackson-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-jaxb-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-netty-http-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-http-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-jetty-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-undertow-starter</artifactId>
</dependency>
<!--<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-rest-swagger-starter</artifactId>
</dependency>-->
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-swagger-java</artifactId>
<version>3.4.0</version>
</dependency>
My Router.java is next:
String listenAddress = "192.168.0.100";
int listenPort = 8080;
restConfiguration()
.component("netty-http")
.scheme("http")
.host(listenAddress)
.bindingMode(RestBindingMode.auto)
.dataFormatProperty("prettyPrint", "true")
.port(listenPort)
.contextPath("/")
// add swagger api-doc out of the box
.apiContextPath("/api-doc")
.apiProperty("api.title", "User API").apiProperty("api.version", "1.2.3")
// and enable CORS
.apiProperty("cors", "true");
// this user REST service is json only
rest("/user").description("User rest service")
.consumes("application/json").produces("application/json")
.get("/{id}").description("Find user by id").outType(User.class)
.param().name("id").type(path).description("The id of the user to get").dataType("int").endParam()
.log("Swagger REST header id: ${header.id}");
If trying to GET http://192.168.0.100:8080/api-doc I'm getting 404.
This route above should print log in Camel terminal when using REST GET with http://192.168.0.100:8080/user/123 or am I wrong? Can't see what's missing.
The context path by default is set to /camel/, which means if rest of your configuration is correct, you should be able to see your api-docs at http://192.168.0.100:8080/camel/api-doc
To override it, you need to set the following property in your application.properties file.
camel.component.servlet.mapping.context-path= /*
For me adding the configuration :
In routes
String listenAddress = "localhost";
int listenPort = 8003;
restConfiguration()
.component("servlet")
.scheme("http")
.host(listenAddress)
.bindingMode(RestBindingMode.auto)
.dataFormatProperty("prettyPrint", "true")
.port(listenPort)
.contextPath("/")
// add swagger api-doc out of the box
.apiContextPath("/api-doc")
.apiProperty("api.title", "User API").apiProperty("api.version", "1.2.3")
// and enable CORS
.apiProperty("cors", "true");
In application.properties
server.port=8003
camel.component.servlet.mapping.context-path=/**
URI
http://localhost:8003/api-doc
I am using camel version : 3.9.0
This solution works fine !!!!

Forward to JSP within Spring Controller after form submission

Using Spring #Controller, #RequestMapping and #ModelAttribute, I'd like to achieve a basic form submission flow in which the user is forwarded to a new JSP with attributes set. Spring provides different ways to achieve this, but I have received various errors.
Example 1
Based on tutorial: https://www.baeldung.com/spring-mvc-form-tutorial
form.html
<form action="/submitForm" method="POST">
<input type="text"id="field1" name="field1">
<!-- other input fields -->
<button type="submit">Submit</button>
</form>
success.jsp
<p>Thanks for signing up ${userName}!!</p>
MyController.java
#Controller
public class MyController{
#RequestMapping(
value = "/submitForm",
method = RequestMethod.POST,
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public String post(#ModelAttribute SignupRequest request, ModelMap model){
// At this point, the SignupRequest is populated correctly
model.addAttribute("userName", request.getUserName());
return "success";
}
}
Results
Using return "success" - the result is HTTP 404 Not Found
Using return "success.jsp", the result is HTTP 405 Request method
'POST' not supported
Using return "redirect:/success.jsp", the client is redirected,
but attributes are not set, and ${userName} is visible.
Example 2
Based on the accepted answer here: Redirect after POST method in spring MVC
MyController.java
#Controller
public class MyController{
#RequestMapping(
value = "/submitForm",
method = RequestMethod.POST,
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public ModelAndView post(#ModelAttribute SignupRequest request){
// At this point, the SignupRequest is populated correctly
ModelAndView mAV = new ModelAndView("redirect:/success.jsp");
mAV.addObject("userName", request.getUserName());
return mAV;
}
}
Result
the client is redirected, but attributes are not set, and ${userName} is visible.
What is the correct way to do this?
Thanks!
EDIT
Additional details
Using SpringBoot with embedded Tomcat. JSP file located in src>main>resources>public. The raw JSP is being served. I believe the project is not treating JSP as it should. Adding POM deps.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-email</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.23.1-GA</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
</dependencies>
#Controller
public class MyController{
#RequestMapping(
value = "/submitForm",
method = RequestMethod.POST,
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public RedirectView post(#ModelAttribute SignupRequest request, RedirectAttributes ra){
// At this point, the SignupRequest is populated correctly
RedirectView rw = new RedirectView();
rw.setUrl("success.jsp");
ra.addFlashAttribute("userName", request.getUserName());
return rw;
}
}

Configure LocaldateTime in Spring Rest API

I use Java 10 with latest Spring spring-boot-starter-parent 2.1.0.RELEASE
POM configuration:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.9.7</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.7</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jaxb-annotations</artifactId>
<version>2.9.7</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.9.7</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.codehaus.woodstox</groupId>
<artifactId>woodstox-core-asl</artifactId>
<version>4.4.1</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.3.0.1</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>1.2.0.Final</version>
</dependency>
<dependency>
<groupId>org.jxls</groupId>
<artifactId>jxls-poi</artifactId>
<version>1.0.15</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>8.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.3.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
</dependencies>
Rest Endpoint:
#GetMapping("{id}")
public ResponseEntity<?> get(#PathVariable String id) {
return transactionRepository
.findById(Integer.parseInt(id))
.map(mapper::toDTO)
.map(ResponseEntity::ok)
.orElseGet(() -> notFound().build());
}
DTO:
public class PaymentTransactionsDTO {
private Integer id;
private String status;
private LocalDateTime created_at;
private String merchant;
.... getters and setters
}
But when I try to return JSON data for LocalDateTime created_at I get empty result. I suppose that LocalDateTime is not properly converted into JSON value.
Can you advice how I can fix this issue?
JSON serialization is driven by Jackson's ObjectMapper, which I recommend configuring explicitely. For proper serialization of the Java 8 date and time objects, make sure to
register the JavaTimeModule
disable writing dates as timestamps
setting the date format (use StdDateFormat)
Description of StdDateFormat:
Default DateFormat implementation used by standard Date
serializers and deserializers. For serialization defaults to using an
ISO-8601 compliant format (format String "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
and for deserialization, both ISO-8601 and RFC-1123.
Recommended configuration:
#Configuration
public class JacksonConfig {
#Bean
public ObjectMapper objectMapper() {
return new ObjectMapper()
.setAnnotationIntrospector(new JacksonAnnotationIntrospector())
.registerModule(new JavaTimeModule())
.setDateFormat(new StdDateFormat())
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
}
}
}
Examples of serialized date and time objects:
LocalDate: 2018-11-21
LocalTime: 11:13:13.274
LocalDateTime: 2018-11-21T11:13:13.274
ZonedDateTime: 2018-11-21T11:13:13.274+01:00
Edit: standalone dependencies (already included transitively in spring-boot-starter-web):
com.fasterxml.jackson.core:jackson-annotations
com.fasterxml.jackson.core:jackson-databind
com.fasterxml.jackson.datatype:jackson-datatype-jsr310
Try using #JsonFormat on your created_at field.
#JsonFormat(pattern="yyyy-MM-dd")
#DateTimeFormat(iso = DateTimeFormat.ISO.TIME)
private LocalDateTime created_at;
You need to add converter and register in spring eg.
baeldung.com/spring-mvc-custom-data-binder
You can type your PaymentTransactionsDTO "created_at" attribute as a String and use a converter to convert the String to LocalDate (type of the attribute created_at of your entity "PaymentTransactions")
#Component
public class PaymentTransactionsConverter implements Converter<PaymentTransactionsDTO, PaymentTransactions> {
#Override
public PaymentTransactions convert(PaymentTransactionsDTO paymentTransactionsDTO) {
PaymentTransactions paymentTransactions = new PaymentTransactions();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
...
paymentTransactions.setCreated_at(LocalDate.parse(paymentTransactionsDTO.getCreated_at(), formatter));
return paymentTransactions;
}
}
My dates defined as LocalDateTime were been serializaded as an array like this:
"timestamp": [
2023,
2,
15,
10,
30,
45,
732425200
],
So following the Peter Walser answer and using some code of that topic, here is what I did in my WebConfig.java:
#Configuration
#EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
// other configs
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
WebMvcConfigurer.super.extendMessageConverters(converters);
converters.add(new MappingJackson2HttpMessageConverter(
new Jackson2ObjectMapperBuilder()
.dateFormat(new StdDateFormat())
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.build()));
}
}
Now everything is good again:
"timestamp": "2023-02-15T10:32:06.5170689",
Try play around with some Jackson builder properties, hope it's been helpful.

How to cache PageImpl with Spring Data Geode?

When trying to cache a PageImpl response from a Spring Data JpaRepository using Spring Data Geode, it fails to cache the result with the following error:
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.domain.PageImpl]: No default constructor found; nested exception is java.lang.NoSuchMethodException: org.springframework.data.domain.PageImpl.<init>()
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:127) ~[spring-beans-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.data.convert.ReflectionEntityInstantiator.createInstance(ReflectionEntityInstantiator.java:64) ~[spring-data-commons-2.0.7.RELEASE.jar:2.0.7.RELEASE]
at org.springframework.data.convert.ClassGeneratingEntityInstantiator.createInstance(ClassGeneratingEntityInstantiator.java:86) ~[spring-data-commons-2.0.7.RELEASE.jar:2.0.7.RELEASE]
at org.springframework.data.gemfire.mapping.MappingPdxSerializer.fromData(MappingPdxSerializer.java:422) ~[spring-data-gemfire-2.0.7.RELEASE.jar:2.0.7.RELEASE]
at org.apache.geode.pdx.internal.PdxReaderImpl.basicGetObject(PdxReaderImpl.java:741) ~[geode-core-9.1.1.jar:?]
at org.apache.geode.pdx.internal.PdxReaderImpl.getObject(PdxReaderImpl.java:682) ~[geode-core-9.1.1.jar:?]
at org.apache.geode.internal.InternalDataSerializer.readPdxSerializable(InternalDataSerializer.java:3054) ~[geode-core-9.1.1.jar:?]
It looks like the MappingPdxSerializer looks for a default constructor but doesn't find it for a PageImpl class.
Here is maven pom for the dependencies I have:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.BUILD-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.BUILD-SNAPSHOT</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-gemfire</artifactId>
</dependency>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.11</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
The JpaRepository I am using is:
#RepositoryRestResource
public interface RecordRepository extends JpaRepository<Record, Long>
{
#Override
#CacheEvict(cacheNames = { "Records" })
<S extends Record> S save(S s);
#Override
#Cacheable(value = "Records")
Optional<Record> findById(Long id);
#Override
#Cacheable(value = "Records", key = "#pageable.pageNumber + '.' + #pageable.pageSize + '.records'")
Page<Record> findAll(Pageable pageable);
#Override
#Cacheable(value = "Records")
Record getOne(Long aLong);
}
The code used to invoke a repository paged result is:
int PAGE=0,PAGE_SIZE=100;
Page<Record> recordPage;
do {
recordPage = recordRepository.findAll(PageRequest.of(PAGE, PAGE_SIZE));
log.info("Retrieved page: [{}]", recordPage);
} while (recordPage.hasNext());
I feel like it maybe a possible bug with the MappingPdxSerializer, but I'm not 100% sure. Any help in resolving this issue would be awesome!
Thanks
Why do you feel this is a possible bug with Spring Data Geode's (SDG) o.s.d.g.mapping.MappingPdxSerializer?
It is quite common, and even expected, that not all objects passed through SDG's MappingPdxSerializer will have a default (i.e. public, no-arg) constructor.
When using such types in your application (e.g. like the SD PageImpl class) and an instance of that type is read from Apache Geode (e.g. get(key)), the object is de-serialized and reconstructed on the (Region) data access operation (providing Apache Geode's read-serialized configuration attribute is not set to true; which cause you other problems and not recommended in this case), then you need to register an EntityInstantiator that informs SDG's MappingPdxSerializer how to instantiate the object, using an appropriate constructor.
The "appropriate" constructor is determined by the persistent entity's PreferredConstructor, which is evaluated during type evaluation by the SD Mapping Infrastructure, and can be specified with the #PersistenceContructor annotation, if necessary. This is useful in cases where you are using 1 of SD's canned EntityIntantiator types, e.g. ReflectionEntityInstantiator, and your application domain type has more than 1 non-default constructor.
Therefore, you can register 1 or more EntityInstantiator objects per application domain object by type using the EntityIntantiatiors composite class, perhaps with a "mapping" between application domain object Class type (e.g. Page) and EntityInstantiator, and then register the EntityInstantiators on SDG's MappingPdxSerializer.
Of course, you need to make sure that custom configured MappingPdxSerializer gets used by Apache Geode...
#Configuration
class ApacheGeodeConfiration {
#Bean
MappingPdxSerializer pdxSerializer() {
Map<Class<?>, EntityInstantiator> customInstantiators = new HashMap<>();
customInstantiators.put(Page.class, new MyPageEntityInstantiator());
customInstantiators.put...
MappingPdxSerializer pdxSerializer =
MappingPdxSerializer.newMappingPdxSerializer();
pdxSerializer.setGemfireInstantiators(
new EntityInstantiators(customInstantiators));
return pdxSerializer;
}
#Bean
CacheFactoryBean gemfireCache(MappingPdxSerializer pdxSerializer) {
CacheFactoryBean gemfireCache = new CacheFactoryBean();
gemfireCache.setPdxSerializer(pdxSerializer);
gemfireCache.set...
return gemfireCache;
}
...
}
Hope this helps!
-j

Spring endpoints without dependency Spring-Boot-Data-REST-Starter

I Have a Repository and Controller,
#RestController
public class PersonController {
#Autowired
PersonRepository repository;
#GetMapping("/people")
public Iterable<Person> getPeople() {
return repository.findAll();
}
#PostMapping("/people")
public void addPerson(#RequestBody Person person) {
repository.save(person);
}
}
and I want to create endpoint /people but this doesn't work without the dependency Spring-Boot-Data-REST-Starter.
The question is : is it possible to create an endpoint without the Spring-Boot-Data-REST-Starter dependency?
here's my dependencies:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
I have a message : Started Application, but the process is finished with exit code 0, so nothing is up.
I should have add this dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

Resources