Spring Boot rest controller not working when package in a jar - java

I am developing a REST API using Spring Boot rest controller. Something strange is happening ; When I test my controller with Eclipse it is working just fine BUT when i deploy the app, packaged in a jar and started with the "java" command line in a docker container then, it doesn't work.
What confuse me is that there is no log. And when I put a sysout at the very beginning of my controller I realized that the controller is not even executed !
Here is the controller with the concerned endpoint, but i am not sure it will help :
#RestController
#RequestMapping("/pdf")
#EnableSwagger2
public class PDFGeneratorResources {
#Autowired
PDFGenerator pdfService;
#Autowired
ResourceLoader resourceLoader;
#PostMapping("/generate-recipies-shoppinglist")
public ResponseEntity<String> generateRecipiesAndShoppingListPDF(#RequestBody List<Day> daysList) {
System.out.println("TRACE");
ResponseEntity<String> responseEntity = null;
String generatedPDFFileURL = "";
try {
generatedPDFFileURL = pdfService.generatePDFFromHTML(PDFTemplates.RecipiesAndShoppingList,
new RecipiesShoppinglistContextBuilder(new ArrayList<Day>(daysList)));
responseEntity = new ResponseEntity<String>(generatedPDFFileURL, HttpStatus.OK);
} catch (Exception e) {
e.printStackTrace();
responseEntity = new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
return responseEntity;
}
}
Question : Is there any way of making spring boot log everything that's happening between tomcat and my controller ? King of --verbose option for spring boot ?
PS:
Here is the DockerFile I am using to deploy the app
FROM registry.gitlab.com/softreaver/meals-ready-backend/runners:centos7jdk11
MAINTAINER MILAZZO_christopher
COPY ./target/*.jar /app.jar
RUN echo -e "/usr/bin/java -Xms128m -Xmx128m -jar /app.jar\n" > /start-app.sh
RUN chmod u+x /start-app.sh
EXPOSE 8080
ENTRYPOINT ["/bin/bash", "/start-app.sh"]

I finally found the problem thx to log.level.root=debug ; I am using the Spring resourceloader to load the template for my PDF service but it seems that it is not able to find the resources folder inside a jar file.
It says : cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/app.jar!/BOOT-INF/classes!/templates/......

I found a solution on internet and made it work by using inputStream :
#Service
public class ResourceLoaderService {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
#Autowired
ResourceLoader resourceLoader;
public String getResourceAbsolutePathString(String location) throws Exception {
Resource resource = resourceLoader.getResource(location);
String absolutePathString = "/";
try {
if (resource.getURL().getProtocol().equals("jar")) {
logger.debug("Jar file system activated");
File tempFile = Files.createTempFile("Mealsready_backend_", null).toFile();
resource.getInputStream().transferTo(new FileOutputStream(tempFile));
absolutePathString = tempFile.getAbsolutePath();
} else {
absolutePathString = resource.getFile().getAbsolutePath();
}
} catch (IOException e) {
logger.error("Error while trying to retrieve a resource : " + e.getMessage());
// TO DELETE Remplacer par un ServiceException
throw new Exception();
}
return absolutePathString;
}
}

Related

How to read project specific META/MANIFEST.MF in Spring Boot Web Application?

I'm working on a Spring Boot MVC application. The requirement is to read the MANIFEST.MF file to get build number and application version number etc of this spring boot app.
For this, I have written the following bean definition for Manifest Class so that I can autowire it in the Controller class.
#Configuration
public class AppConfig{
#Bean("manifest")
public java.util.jar.Manifest getManifest()
{
// get the full name of the application manifest file
String appManifestFileName = this.getClass().getProtectionDomain().getCodeSource().getLocation().toString() + JarFile.MANIFEST_NAME;
Enumeration resEnum;
try
{
// get a list of all manifest files found in the jars loaded by the app
resEnum = Thread.currentThread().getContextClassLoader().getResources(JarFile.MANIFEST_NAME);
while (resEnum.hasMoreElements())
{
try
{
URL url = (URL) resEnum.nextElement();
System.out.println("Resource url=" + url.toString());
// is the app manifest file?
if (url.toString().equals(appManifestFileName))
{
// open the manifest
InputStream is = url.openStream();
if (is != null)
{
// read the manifest and return it to the application
Manifest manifest = new Manifest(is);
return manifest;
}
}
}
catch (Exception e)
{
// Silently ignore wrong manifests on classpath?
}
}
}
catch (IOException e1)
{
// Silently ignore wrong manifests on classpath?
}
return null;
}
}
The above code is taken from here. But it didn't help. It is always giving me null object.
AppController.java
#RestController
public class AppController
{
#Autowired
private Environment env;
#Autowired
#Qualifier("manifest")
private Manifest manifest;
#GetMapping("/get-app-details")
public String getAppDetails()
{
Attributes mainAttributes = manifest.getMainAttributes();
String buildNum = mainAttributes.getValue("Build-Number");
buildNum = buildNum.substring(buildNum.lastIndexOf('_') + 1);
String AppVersion = env.getProperty("App.Version") + "." + buildNum;
return "Build Number - " + buildNum + ", AppVersion - " + AppVersion;
}
}
Additional info - I'm using gradle to build this application as a war file and deploying it into external tomcat version 9.

Spring Boot Creating endpoint for download logs

I created an endpoint in spring boot to download logs of the application:
#Service
public class LogService {
public byte[] obterLog() {
try {
InputStream inputStream = new ClassPathResource("spring.log").getInputStream();
byte[] log = FileCopyUtils.copyToByteArray(inputStream);
return log;
} catch (IOException e) {
throw new FileException(e.getMessage());
}
}
And the controller
#Autowired
private LogService logService;
#GetMapping
public ResponseEntity<byte[]> getLog() {
byte[] log = logService.obterLog();
return ResponseEntity.ok().body(log);
}
But I can only get the log on the second time that I run the application and the log file is on the target/classes folder.
On the first time that I run the application I get a exception:
Class path resource [spring.log] cannot be opened because it does not exist
Why is this happening?
Yes the exception is right. When there are logs, it start printing into .log file and if it is not there, it will create one. In your case you could log something in when the app starts.
You could try something like this and see if the file exist and log something and then try again.
Path path = Paths.get("/path/to/spring.log");
// file exists and it is not a directory
if(Files.exists(path) && !Files.isDirectory(path)) {
log.info("file created");
}

Not able to save the image to disk in linux using springboot

I am trying to save images to disk using spring boot and angular, however there are no
exceptions thrown in the below code nor any errors, but i cannot see image in the required folder
#RestController
#CrossOrigin(origins = "http://localhost:4200")
public class ImageController {
#RequestMapping(value = "/postImages", method = RequestMethod.POST, consumes =
MediaType.MULTIPART_FORM_DATA_VALUE )
public ResponseEntity<Void> uploadPolicyDocument(#RequestParam("image")
List<MultipartFile> multipartFile)
{
String OUT_PATH = "home\\krishnachaitanya\\Pictures\\testing\\";
try {
for(MultipartFile mf: multipartFile)
{
byte[] bytes = mf.getBytes();
Path path = Paths.get(OUT_PATH+ mf.getOriginalFilename());
Files.write(path, bytes);
}
} catch (IOException e) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
return ResponseEntity.ok().build();
}
Actually I think the file is successfully written, but not in the place you would expect. '\' is not a path separator on Linux and the path you specify is relative, so the file is written in the applications working directory. The file is named: home\krishnachaitanya\Pictures\testing\oryginalFileName.
Change the OUT_PATH to "/home/krishnachaitanya/Pictures/testing/"
The OUT_PATH looks very wrong for a linux system. have you tried to use "/" instead of "\\"

Can REST-API controller packaged in JAR be called?

I have packaged and deployed my TestRestController.java(PFB code) in a JAR(testrest.jar) in an EAR in JBOSS EAP-6.2,
How can I access my REST-API, i tried hitting the http://{WEB-SERVER-IP}:8080/testrest/test/execute URL from a REST client? But I get HTTP 404.
Is it even possible?
TestRestController.java:
#Path("/test")
public class TestRestController
{
#POST
#Path("/execute")
#Consumes(MediaType.APPLICATION_JSON)
public Response executeRestApi(TestControllerDTO testControllerDto)
{
try
{
if (validateRequestParams(testControllerDto))
{
System.out.println("Validation success.");
response = Response.status(Status.OK).entity("Validation success.").build();
}
else
{
System.out.println("Validation failed.");
response = Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("Validation failed.").build();
}
}
catch (Exception e)
{
response = Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("Validation failed.").build();
}
return response;
}
private boolean validateRequestParams(TestControllerDTO testControllerDto)
{
boolean areParamsValid = false;
if (null != testControllerDto)
{
areParamsValid = true;
}
return areParamsValid;
}
}
Please help me.
P.S. : I am a newbie to Java and REST.
Thanks in advance.
You need to initiate the rest servlet somehow. The easiest way is to just add an javax.ws.rs.core.Application with an #ApplicationPath annotation to your application.
#ApplicationPath("/rest")
public class JaxRSApplication extends Application {
}
It can be left empty. It can packaged either in your .jar or in the .war (keep in mind, the .jar should also be included in the war in the WEB-INF/lib). With this the rest servlet will get initialized automatically and the classpath will be scanned for your resource classes annotated with #Path
You can see other deployment options here and for more detailed information, you can see the spec.
With the above Application class, you should be able to access
http://localhost:8080/my-app/rest/test/execute

open a file in a tomcat webapplication

i want to open a file and return its content. Although it is in the same directory like the class that wants to open the file, the file can't be found. Would be cool if you could help me solving the problem.
Here is the code:
#GET #Produces("text/html") #Path("/{partNO}/") #Consumes("text/html")
public String getPartNoResponseHTML(#PathParam("partNO") String parID) throws WebApplicationException {
PartNoTemplate partNo = getPartNoResponse(parID);
String result = "";
try {
result = readFile(PART_NO_TEMPLATE_FILE);
} catch (FileNotFoundException e) {
e.printStackTrace(System.out);
return e.getMessage() + e.toString();
// throw new WebApplicationException(Response.Status.NOT_FOUND);
} finally {
result = result.replace("{partNO}", parID);
result = result.replace("{inputFormat}", partNo.getFormat().toString());
}
return result;
}
I guess it can't find the file, because its running on tomcat. I'm also using Jersey and JAX-RS. Thank you for your help,
Maxi
If the file is inside the application WAR (or in a jar) you can try by using
InputStream input = servletContext.getClass().getClassLoader().getResourceAsStream("my_filename.txt");
Your problem is similar (I think) with How can I read file from classes directory in my WAR?
Try to get the path of the file from ServletContext.
ServletContext context = //Get the servlet context
In JAX-RS to get servlet context use this:
#javax.ws.rs.core.Context
ServletContext context;
Then get the file from your web application:
File file = new File(context.getRealPath("/someFolder/myFile.txt"));
You don't post the code that actually tries to read the file, but assuming the file is in the classpath (as you mention it's in the same directory as the class) then you can do:
InputStream in = this.getClass().getResourceAsStream("/SomeTextFile.txt");
See here

Categories