Spring MVC中JAX-RS服务@Autowired注入ProductServices为空求助
Hey, let's break down your issue and fix it step by step!
The Core Problem
Your GenericResource (JAX-RS endpoint) isn't managed by the Spring container—Jersey (your JAX-RS implementation) instantiates it directly. That's why @Autowired ProductServices is null, while your regular Spring controller works fine (Spring creates and manages those beans).
You also have a bug in your custom MessageBodyWriter that prevents proper XML serialization of your List<Product>.
Fix 1: Make JAX-RS Resources Spring-Managed
There are two clean ways to fix the @Autowired null issue:
Option A: Use Spring Boot's Jersey Auto-Configuration (Recommended)
First, mark your GenericResource as a Spring component so Spring knows about it:
@Component // Add this annotation to let Spring manage this class @Path("release") public class GenericResource { @Context private UriInfo context; @Autowired private ProductServices productServices; public GenericResource() { } @GET @Produces(MediaType.APPLICATION_XML) public List<Product> getXml() { return productServices.getProductList(); } }
Then simplify your restConfig to let Spring auto-discover JAX-RS endpoints:
@Component @ApplicationPath("TransferPermit/Slsi_Customs/restAPI") public class restConfig extends Application { // No need to override getClasses—Spring will scan for @Path beans automatically }
Option B: Manual Spring Context Lookup (Not Recommended)
If you don't want Spring to manage the resource, you can manually fetch the bean from the Spring context, but this adds tight coupling:
@Path("release") public class GenericResource { @Context private UriInfo context; private ProductServices productServices; public GenericResource() { ApplicationContext springContext = new AnnotationConfigApplicationContext(YourSpringConfig.class); productServices = springContext.getBean(ProductServices.class); } @GET @Produces(MediaType.APPLICATION_XML) public List<Product> getXml() { return productServices.getProductList(); } }
Fix 2: Fix XML Serialization (MessageBodyWriter)
Your custom restConverter has two critical issues:
isWriteablechecks ifProductis assignable to the type (which isList), so it will always return false.writeTooutputst.toString()—this just prints object memory addresses, not valid XML.
Simplest Solution: Use JAXB Wrapper Class (No Custom Writer Needed)
Jersey's default JAXB support can't serialize raw List objects directly, but it works great with a wrapper class. Create a simple wrapper for your product list:
@XmlRootElement(name = "products") public class ProductListWrapper { private List<Product> productList; // JAXB requires a no-arg constructor public ProductListWrapper() {} public ProductListWrapper(List<Product> productList) { this.productList = productList; } @XmlElement(name = "product") public List<Product> getProductList() { return productList; } public void setProductList(List<Product> productList) { this.productList = productList; } }
Then update your GenericResource to return this wrapper:
@GET @Produces(MediaType.APPLICATION_XML) public ProductListWrapper getXml() { return new ProductListWrapper(productServices.getProductList()); }
You can now delete your custom restConverter—Jersey will handle XML serialization automatically thanks to the @XmlRootElement annotations on Product and ProductListWrapper.
If You Must Keep the Custom MessageBodyWriter
If you need custom XML handling, fix the writer like this:
@Provider @Produces(MediaType.APPLICATION_XML) public class restConverter implements MessageBodyWriter<List<Product>> { @Override public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { // Check if the type is List and its generic parameter is Product if (!List.class.isAssignableFrom(type)) return false; if (!(genericType instanceof ParameterizedType)) return false; ParameterizedType paramType = (ParameterizedType) genericType; Type[] typeArgs = paramType.getActualTypeArguments(); return typeArgs.length == 1 && typeArgs[0].equals(Product.class); } @Override public long getSize(List<Product> t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { return -1; // Let the container calculate size automatically } @Override public void writeTo(List<Product> products, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException { try { // Use JAXB to serialize the list via our wrapper class JAXBContext jaxbContext = JAXBContext.newInstance(ProductListWrapper.class); Marshaller marshaller = jaxbContext.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(new ProductListWrapper(products), entityStream); } catch (JAXBException e) { throw new WebApplicationException("Failed to serialize products to XML", e); } } // Reuse the ProductListWrapper class from earlier here @XmlRootElement(name = "products") public static class ProductListWrapper { private List<Product> productList; public ProductListWrapper() {} public ProductListWrapper(List<Product> productList) { this.productList = productList; } @XmlElement(name = "product") public List<Product> getProductList() { return productList; } public void setProductList(List<Product> productList) { this.productList = productList; } } }
Fix 3: Update Dependencies (Optional but Recommended)
Replace your jaxrs-ri dependency with Spring Boot's official Jersey starter to avoid version conflicts and get better integration:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jersey</artifactId> </dependency>
Final Verification
- Start your Spring Boot app
- Visit
http://localhost:8080/TransferPermit/Slsi_Customs/restAPI/release - You should see a properly formatted XML response with your product data.
内容的提问来源于stack exchange,提问作者vidarshana

