Class nor any of its super class is known to this context

nixgadget picture nixgadget · Feb 9, 2017 · Viewed 12.2k times · Source

Im trying to understand this particular issue i'm having. Using Spring OXM here to implement a Soap WS Consumer.

I'm only attaching the relevant information to explain the problem.

LoginWsConfiguration,

@Configuration
public class LoginWsConfiguration {

    @Inject
    private OnboardingProperties onboardingProperties;

    @Bean
    Jaxb2Marshaller jaxb2Marshaller() {
        Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
        jaxb2Marshaller
            .setPackagesToScan("org.openiam.ws.login.api_3_2_6");
        try {
            jaxb2Marshaller.afterPropertiesSet();
        }
        catch (Exception ex) {
            throw new BeanCreationException(ex.getMessage(), ex);
        }
        return jaxb2Marshaller;
    }

    @Bean
    public WebServiceTemplate webServiceTemplate(Jaxb2Marshaller jaxb2Marshaller) {
        WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
        webServiceTemplate.setMarshaller(jaxb2Marshaller);
        webServiceTemplate.setUnmarshaller(jaxb2Marshaller);
        webServiceTemplate.setDefaultUri(onboardingProperties.getIAM().getEndpoint().getLogin());

        return webServiceTemplate;
    }

And the LoginClient client is implemented as,

@Component
public class LoginClient {

    private static final Logger log = LoggerFactory.getLogger(IAMLoginClient.class);

    @Autowired
    private LoginMapper loginMapper;

    @Inject
    private OnboardingProperties onboardingProperties;

    private WebServiceTemplate webServiceTemplate;

    @Autowired
    public LoginClient(WebServiceTemplate webServiceTemplate) {
        this.webServiceTemplate = webServiceTemplate;
    }

    public LoginClient() {
    }

    public Optional getLoginByUserId(final String userId) {
        ObjectFactory factory = new ObjectFactory();
        GetLoginByUser req = factory.createGetLoginByUser();
        req.setUserId(userId);
        GetLoginByUserResponse resp = (GetLoginByUserResponse)webServiceTemplate.marshalSendAndReceive(req);
        if (resp != null && resp.getReturn() != null && resp.getReturn().getStatus() == org.openiam.ws.login.api_3_2_6.ResponseStatus.SUCCESS) {
            List<Login> foundLogins = resp.getReturn().getPrincipalLists();
            Login foundLogin = foundLogins.stream()
                .filter(login -> login.getManagedSysId().equals(Constants.IAM_DEFAULT_MANAGED_SYS_ID))
                .findFirst()
                .orElse(null);
            return Optional.ofNullable((foundLogin != null) ? this.loginMapper.mapIAMLogin(foundLogin) : null);
        }
        return Optional.empty();
    }

For completeness, GetLoginByUser,

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "getLoginByUser", propOrder = {
    "userId"
})
@XmlRootElement(name = "getLoginByUser")
public class GetLoginByUser {

    protected String userId;

    /**
     * Gets the value of the userId property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getUserId() {
        return userId;
    }

    /**
     * Sets the value of the userId property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setUserId(String value) {
        this.userId = value;
    }

}

GetLoginByUserResponse,

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "getLoginByUserResponse", propOrder = {
    "_return"
})
@XmlRootElement(name = "getLoginByUserResponse")
public class GetLoginByUserResponse {

    @XmlElement(name = "return")
    protected LoginListResponse _return;

    /**
     * Gets the value of the return property.
     * 
     * @return
     *     possible object is
     *     {@link LoginListResponse }
     *     
     */
    public LoginListResponse getReturn() {
        return _return;
    }

    /**
     * Sets the value of the return property.
     * 
     * @param value
     *     allowed object is
     *     {@link LoginListResponse }
     *     
     */
    public void setReturn(LoginListResponse value) {
        this._return = value;
    }

}

However, when I try to,

@Autowired
private UserClient iamUserClient;

@Autowired
private LoginClient iamLoginClient;

Optional<IAMUser> userFromIAM = iamUserClient.getUserByPrincipal(lowercaseLogin);
IAMUser userIAM = userFromIAM.
        orElseThrow(() -> new UsernameNotFoundException("User " + lowercaseLogin + " was not found in IAM"));
    if (userIAM.getStatus() != IAMUserStatus.ACTIVE || userIAM.getAccountStatus() != null) {
        throw new UserNotActivatedException("User " + lowercaseLogin + " is not active");
    }
Optional<IAMLogin> loginFromIAM = iamLoginClient.getLoginByUserId(userIAM.getId());

I get the error,

org.springframework.oxm.UncategorizedMappingException: Unknown JAXB exception; nested exception is javax.xml.bind.JAXBException: class org.openiam.ws.login.api_3_2_6.GetLoginByUser nor any of its super class is known to this context.
    at org.springframework.oxm.jaxb.Jaxb2Marshaller.convertJaxbException(Jaxb2Marshaller.java:915)
    at org.springframework.oxm.jaxb.Jaxb2Marshaller.marshal(Jaxb2Marshaller.java:684)
    at org.springframework.ws.support.MarshallingUtils.marshal(MarshallingUtils.java:81)
    at org.springframework.ws.client.core.WebServiceTemplate$2.doWithMessage(WebServiceTemplate.java:399)
    at org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:590)
    at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:555)
    at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:390)
    at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:383)
    at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:373)
    at com.orchestral.dsm.onboarding.iam.ws.login.LoginClient.getLoginByUserId(LoginClient.java:77)
    at com.orchestral.dsm.onboarding.security.IAMUserDetailsService.loadUserByUsername(IAMUserDetailsService.java:45)

From what I can see it doesn't fail when marshalling in getUserByPrincipal (UserClient) but fails on getLoginByUserId (LoginClient).

Answer

nixgadget picture nixgadget · Feb 11, 2017

This was due to the fact that both,

@Autowired
private UserClient iamUserClient;

@Autowired
private LoginClient iamLoginClient;

were conflicting with each other. Having individual jaxb2Marshaller and passing that to WebServiceTemplate fixed the issue.

So LoginWsConfiguration updated to,

@Configuration
public class LoginWsConfiguration {

    @Bean
    Jaxb2Marshaller jaxb2LoginMarshaller() {
        Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
        jaxb2Marshaller.setPackagesToScan("org.openiam.ws.login.api_3_2_6");
        return jaxb2Marshaller;
    }

    @Bean
    public LoginClient loginClient(Jaxb2Marshaller jaxb2LoginMarshaller) {
        LoginClient client = new LoginClient();
        client.setMarshaller(jaxb2LoginMarshaller);
        client.setUnmarshaller(jaxb2LoginMarshaller);
        client.setDefaultUri("uri");

        return client;
    }
}