4

I have a multiple Spring Boot microservice apps managed by Gradle. There is a common jar and domain specific jars organized like so:

| common/
|-- common.jar
| p/
|-- p-ingest.jar
| g/
|-- g-ingest.jar

My common jar has a class, BaseRESTService, that autowires HttpServletRequest (which I already know is a bad idea - not my code). The p-ingest.jar imports common, as does the g-ingest jar. geoalloc runs without problem. But p-ingest, which was literally copied from g-ingest, does not run. p-ingest gets the following exception when the context attempts to initialize:

Field request in com.company.common.BaseRESTService required a bean of type 'javax.servlet.http.HttpServletRequest' that could not be found.

I'm not new to Spring, and I understand component scanning and autowiring and all that, but I've been working on this for 2 days and I cannot figure what's happening. I ran gradle dependencies on both projects, and the trees are identical. Below is the boot application class of p-ingest:

@SpringBootApplication
@ComponentScan(
        basePackageClasses = com.company.common.ConfigurationSearchCriteriaFactory.class,
        basePackages = {"com.company.erd"})
@EnableJpaRepositories(basePackages = "com.company.erd")
@EntityScan(basePackages = {"com.company.erd"})
public class PortfolioRiskIngestApplication implements ApplicationRunner {

    private static final Log logger = LogFactory.getLog(IngestApplication.class);
    @Autowired
    private IngestService ingestService;

    public PIngestApplication(PIngestService ingestService) {this.ingestService = ingestService;}

    public static void main(String[] args) {

        SpringProfileHelper.setProfileFromAwsEnvironment();
        SpringApplication app = new SpringApplication(PIngestApplication.class);
        app.setWebEnvironment(false);
        app.run(args);
    }

    @PostConstruct
      void started() {
        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
      }

    @Override
    public void run(ApplicationArguments applicationArguments) {
        // define the log info
        LogInfo info = LogInfo.newInstance("run", new Object[] { StringUtility.arrayToString(applicationArguments.getSourceArgs()) });

        // log entry
        logger.info(info.entry());

        ingestService.run(applicationArguments.getSourceArgs());

        // log exit
        logger.info(info.exit());
    }
}

And here is an excerpt from BaseRestService:

public class BaseRESTService 
{
    private static final Log logger = LogFactory.getLog(BaseRESTService.class);

    @Autowired
    private HttpServletRequest request;

    @ResponseStatus(HttpStatus.NOT_FOUND)  
    @ExceptionHandler(value = EntityNotFoundException.class)  
    public ErrorResponse handleEntityNotFoundException(EntityNotFoundException e){  
        ErrorResponse errorResponse = new ErrorResponse();
        errorResponse.setErrorCode(HttpStatus.NOT_FOUND.value());
        errorResponse.setErrorMessage(e.getMessage());
        logger.error(e.getMessage(), e);
        return errorResponse;  
    } 

Nothing special. All classes involved are pretty straightforward. I welcome ANY ideas that anyone has as to what I'm doing wrong...

CNDyson
  • 1,687
  • 7
  • 28
  • 63
  • Well, you have `app.setWebEnvironment(false);`. So your app is not a web application. So it can't use HttpServletRequest, which is a request coming over the web to a servlet, thus requiring the app to be a web application. – JB Nizet Oct 10 '19 at 22:20
  • All of our microservices set that to false, and they work. How could that be? – CNDyson Oct 10 '19 at 22:23
  • I don't know, and I might be wrong in thinking that it's what prevents the usage of HttpServletRequest, but I don't understand why you would tell Spring that you don't work in a web environment when you clearly are and want to. Please post the complete stack trace of the exception. – JB Nizet Oct 10 '19 at 22:32
  • There is no stacktrace. We do have a health check controller that needs to run though... I guess you're right! But at least 5 developers have looked at this with me, and no one caught that. – CNDyson Oct 10 '19 at 22:34
  • I'm told that setting the web environment to `true` isn't what we want. That will keep the application always alive, and we need it to lie dormant until it's woken up, and then terminate. Like I said, other apps are successfully doing this... – CNDyson Oct 11 '19 at 15:19

2 Answers2

2

I figured out my problem, and it was a rookie mistake. Out of laziness, I did a component scan across our entire codebase, which picked up the controller we had in the common jar that was only meant for our REST application. Component scanning only the actual desired packages worked.

CNDyson
  • 1,687
  • 7
  • 28
  • 63
1

You can get HttpServletRequest using RequestContext

@Inject
private RequestContext requestContext;

And call getRequest() in method:

HttpServletRequest request = requestContext.getRequest();
Ori Marko
  • 56,308
  • 23
  • 131
  • 233
  • Thanks for your answer, but changing the code isn't an option. All of our microservices inject the `HttpServletRequest`. What I need is a deployment solution. – CNDyson Oct 15 '19 at 10:54