You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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:

  1. isWriteable checks if Product is assignable to the type (which is List), so it will always return false.
  2. writeTo outputs t.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; }
    }
}

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

  1. Start your Spring Boot app
  2. Visit http://localhost:8080/TransferPermit/Slsi_Customs/restAPI/release
  3. You should see a properly formatted XML response with your product data.

内容的提问来源于stack exchange,提问作者vidarshana

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:47:45