Как вызвать веб-службу RESTful с Spring Secuirty с параметрами POST из приложения для Android

У меня есть веб-приложение Spring MVC, защищенное с помощью Spring Secuirty, и оно настроено с использованием аннотаций Java, это классы конфигурации безопасности приложения My Spring MVC

package seguridad;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;



@Configuration
@EnableWebSecurity
//@EnableWebMvcSecurity

public class SeguridadConfiguracion extends WebSecurityConfigurerAdapter {

    @Autowired 
    private AutenticarProvider autenticador;

    @Override
    protected void configure( HttpSecurity http ) throws Exception 
    {
        http
            .authenticationProvider(autenticador)
            .authorizeRequests()
                .antMatchers("/resources/**").permitAll()
                .antMatchers("/css/**").permitAll() 
                .antMatchers("/js/**").permitAll()
                .antMatchers("/img/**").permitAll() 
                .antMatchers("/sound/**").permitAll() 
                .antMatchers("/fonts/**").permitAll()
                .antMatchers("/ajax/**").permitAll()
                .antMatchers("/php/**").permitAll()
                .antMatchers("/xml/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                    .loginPage("/login/login")
                    .permitAll()
                    .and()
                .logout()                                    
                    .permitAll()
                    .logoutSuccessUrl("/login/login?logout")
                .and()
                    .csrf().disable();
    }

}

Мой AuthProvider

@Component
public class AutenticarProvider implements AuthenticationProvider {

    @Override
    public Authentication authenticate(Authentication authentication)
            throws AuthenticationException {

        String name = null;
        String password = null;
        Authentication auth = null;
        boolean pruebaLDAP = false;

        try {
            name = authentication.getName();
            password = authentication.getCredentials().toString();


            if (name.equals("user") && password.equals("MyPassword")) 
            {
                List<GrantedAuthority> grantedAuths = new ArrayList<>();
                grantedAuths.add(new SimpleGrantedAuthority("PERMISO_PRIMERO"));
                grantedAuths.add(new SimpleGrantedAuthority("PERMISO_MODIFICAR_PERMISO"));
                grantedAuths.add(new SimpleGrantedAuthority("PERMISO_CONSULTAR_PERMISO"));

                auth = new UsernamePasswordAuthenticationToken(name, password, grantedAuths);
            }

            } catch (AuthenticationException e) {
                e.printStackTrace();
                throw e;
            }

            return auth;
        }

        @Override
        public boolean supports(Class<?> authentication) {
            return authentication.equals(UsernamePasswordAuthenticationToken.class);
        }

Это мой класс контроллера метода Restful веб-службы, который я хочу вызвать. Метод получает строку JSON, затем я получаю значения, которые хочу, из строки JSON, а затем присваиваю эти значения объекту POJO, а затем возвращаю объект

@Controller
@RequestMapping("/jsp/")
public class InicioControlador {



    @RequestMapping(value = "changeNameAfter", method = RequestMethod.POST)
    public @ResponseBody
    Person methodChangeStringPro(@RequestBody final String json, Model model)
            throws IOException {

        ObjectMapper mapper = new ObjectMapper();

        Map<String, String> StringValues;
        StringValues = mapper.readValue(json, HashMap.class);

        String stringId = StringValues.get("id");
        String name = StringValues.get("name");

        System.out.println("EL STRING ID vale " + stringId);
        System.out.println("EL name  vale " + name);

        int realId = Integer.parseInt(stringId);

        String newName = name + "KEK";
        realId = realId + 1;

        Person person = new Person();
        person.setName(newName);
        person.setId(realId);


        return person;
    }
}

И это код из моего приложения для Android, где я пытаюсь вызвать этот метод

Мой основной класс деятельности

public class MainActivity extends AbstractAsyncActivity {

protected static final String TAG = MainActivity.class.getSimpleName();

// ***************************************
// Activity methods
// ***************************************

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // Initiate the request to the protected service
    final Button submitButton = (Button) findViewById(R.id.submit);
    submitButton.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            new FetchSecuredResourceTask().execute();
        }
    });
}

// ***************************************
// Private methods
// ***************************************
private void displayResponse(Person response) {
    Toast.makeText(this, response.getName(), Toast.LENGTH_LONG).show();
}

// ***************************************
// Private classes
// ***************************************
private class FetchSecuredResourceTask extends AsyncTask<Void, Void, Person> {

    private String username;

    private String password;

    @Override
    protected void onPreExecute() {
        showLoadingProgressDialog();

        // build the message object
        EditText editText = (EditText) findViewById(R.id.username);
        this.username = editText.getText().toString();

        editText = (EditText) findViewById(R.id.password);
        this.password = editText.getText().toString();
    }

    @Override
    protected Person doInBackground(Void... params) {
        final String url = "http://10.0.2.2:8080/ProyectoServidor/jsp/changeNameAfter";

        // Populate the HTTP Basic Authentitcation header with the username
        // and password
        HttpAuthentication authHeader = new HttpBasicAuthentication(username, password);
        HttpHeaders requestHeaders = new HttpHeaders();
        requestHeaders.setAuthorization(authHeader);
        requestHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));

        // Create a new RestTemplate instance
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getMessageConverters().add(new MappingJacksonHttpMessageConverter());

        //Set OBJECT to send
        Person personToSend = new Person();
        personToSend.setId(23);
        personToSend.setName("Prueba");


        HttpEntity entityPerson = new HttpEntity(personToSend, requestHeaders);

        try {
            // Make the network request
            Log.d(TAG, url);
            ResponseEntity<Person> response = restTemplate.exchange(url, HttpMethod.POST,
                    entityPerson, Person.class);
            return response.getBody();
        } catch (HttpClientErrorException e) {
            Log.e(TAG, e.getLocalizedMessage(), e);
            return new Person();
        } catch (ResourceAccessException e) {
            Log.e(TAG, e.getLocalizedMessage(), e);
            return new Person();
        }
    }

    @Override
    protected void onPostExecute(Person result) {
        dismissProgressDialog();
        displayResponse(result);
    }

}

Мой класс AbstractAsyncActivity

public class AbstractAsyncActivity extends Activity {

protected static final String TAG = AbstractAsyncActivity.class.getSimpleName();

private ProgressDialog progressDialog;

private boolean destroyed = false;

// ***************************************
// Activity methods
// ***************************************
@Override
protected void onDestroy() {
    super.onDestroy();
    destroyed = true;
}

// ***************************************
// Public methods
// ***************************************
public void showLoadingProgressDialog() {
    this.showProgressDialog("Loading. Please wait...");
}

public void showProgressDialog(CharSequence message) {
    if (progressDialog == null) {
        progressDialog = new ProgressDialog(this);
        progressDialog.setIndeterminate(true);
    }

    progressDialog.setMessage(message);
    progressDialog.show();
}

public void dismissProgressDialog() {
    if (progressDialog != null && !destroyed) {
        progressDialog.dismiss();
    }
}
}

Я думаю, что проблема в этой строке из моего класса Main Activity

// Populate the HTTP Basic Authentitcation header with the username
        // and password
        HttpAuthentication authHeader = new HttpBasicAuthentication(username, password);
        HttpHeaders requestHeaders = new HttpHeaders();
        requestHeaders.setAuthorization(authHeader);
        requestHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));

        // Create a new RestTemplate instance
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getMessageConverters().add(new MappingJacksonHttpMessageConverter());

        //Set OBJECT to send
        Person personToSend = new Person();
        personToSend.setId(23);
        personToSend.setName("Prueba");

        HttpEntity entityPerson = new HttpEntity(personToSend, requestHeaders);

        try {
            // Make the network request
            Log.d(TAG, url);
            ResponseEntity<Person> response = restTemplate.exchange(url, HttpMethod.POST,
                    entityPerson, Person.class);
            return response.getBody();
        } catch (HttpClientErrorException e) {
            Log.e(TAG, e.getLocalizedMessage(), e);
            return new Person();
        } catch (ResourceAccessException e) {
            Log.e(TAG, e.getLocalizedMessage(), e);
            return new Person();
        }

Поскольку ОШИБКА, которую я получаю в своем LogCat,

10-16 00:33:51.054: E/AndroidRuntime(1481): Caused by: org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [modelo.Person] and content type [text/html;charset=ISO-8859-1]

Я следовал этому руководству, но адаптировал его для своих нужд https://github.com/spring-projects/spring-android-samples/tree/master/spring-android-basic-auth

Я использую следующие библиотеки

jackson-core-asl-1.9.11.jar
jackson-mapper-asl-1.9.13.jar
spring-android-core-1.0.0.RELEASE.jar
spring-android-rest-template-1.0.1.RELEASE.jar

EDIT Пользователь @ravindra classNotFoundError был вызван тем, что я использовал jackson-core-asl-1.9.11.jar вместо jackson-core-2.6.1.jar после того, как добавил этот .JAR, а этот jackson-annotations-2.6.1.jar исключение класса не найдено было устранено. Но у меня все еще есть исходная ошибка 10-16 04:44:37.524: E/AndroidRuntime(1349): Caused by: org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [modelo.Person] and content type [text/html;charset=ISO-8859-1] , которая заставила меня задать этот вопрос.

Это изменения, которые я сделал, и когда я думаю, что это проблема

// Populate the HTTP Basic Authentitcation header with the username
        // and password
        HttpAuthentication authHeader = new HttpBasicAuthentication(username, password);
        HttpHeaders requestHeaders = new HttpHeaders();
        requestHeaders.setAuthorization(authHeader);
        requestHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));

        // Create a new RestTemplate instance
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());

        // Set OBJECT to send
        Person personToSend = new Person();
        personToSend.setId(23);
        personToSend.setName("Prueba");

        HttpEntity<Person> entityPerson = new HttpEntity<Person>(personToSend, requestHeaders);

        try {
            String json = "";

            JSONObject jsonObject = new JSONObject();

            jsonObject.accumulate("id", "2");
            jsonObject.accumulate("name", "hola");
            json = jsonObject.toString();

            // Make the network request
            Log.d(TAG, url);

            ResponseEntity<Person> response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<Object>(requestHeaders), Person.class);
            return response.getBody();

Я пытался использовать MappingJackson2HttpMessageConverter в качестве своего конвертера, как это предлагается здесь в подобных вопросах:

Заставить Spring RestTemplate использовать XmlConverter и Не удалось извлечь ответ: не найден подходящий HttpMessageConverter для типа ответа, но все же я получаю та же ошибка

но все же я получаю ту же ошибку `10-16 04:44:37.524: E/AndroidRuntime (1349): вызвано: org.springframework.web.client.RestClientException: не удалось извлечь ответ: не найден подходящий HttpMessageConverter для типа ответа [ modelo.Person] и тип контента [text/html;charset=ISO-8859-1]

РЕДАКТИРОВАТЬ 2:

Я изменил аннотации своего контроллера и добавил produces = "application/json" в метод RequestMappin следующим образом.

@RequestMapping(value = "changeNameAfter", method = RequestMethod.POST, produces = "application/json")
    public @ResponseBody
    Person methodChangeStringPro(@RequestBody final String json, Model model)
            throws IOException {

Но все же это дает мне ту же ошибку.

E/AndroidRuntime(1349): Caused by: org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [modelo.Person] and content type [text/html;charset=ISO-8859-1]

person StackQuestion    schedule 16.10.2015    source источник
comment
Взгляните на stackoverflow.com/questions/ 13038529/ и stackoverflow.com/questions/24723394/. Я подозреваю, что проблема с настройкой Content-Type в заголовках   -  person Ravindra babu    schedule 16.10.2015
comment
в первой ссылке они использовали XML, а не JSON, во второй ссылке они рекомендовали использовать MappingJackson2HttpMessageConverter, поэтому я добавил следующую библиотеку jackson-databind-2.6.1.jar в мою папку libs, но теперь, когда у меня есть класс, не найденный ошибка 10 -16 03:12:53.961: E/AndroidRuntime(1324): вызвано: java.lang.NoClassDefFoundError: com.fasterxml.jackson.databind.ObjectMapper 10-16 03:12:53.961: E/AndroidRuntime(1324): в org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.‹init›(MappingJackson2HttpMessageConverter.java:55)   -  person StackQuestion    schedule 16.10.2015
comment
Вы также добавили databind-2.6.1.jar во время выполнения Java? Сформируйте ошибку, кажется, что jar не находится в пути к классам   -  person Ravindra babu    schedule 16.10.2015
comment
Я импортирую библиотеку в свою папку libs, а затем щелкаю банку и выбираю «Добавить в путь сборки», я использую eclipse   -  person StackQuestion    schedule 16.10.2015
comment
Вы не установили заголовки, как объяснено в двух других вопросах SE, касающихся типа контента.   -  person Ravindra babu    schedule 16.10.2015
comment
@ravindra, можете ли вы дать ответ или привести пример того, как установить заголовки, я думаю, что они устанавливаются, когда я делаю это requestHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); также может ли эта ошибка означать, что у меня где-то плохая конфигурация безопасности, а возвращаемый текст/html является html-страницей с сообщением 404 или отказом в доступе или чем-то подобным? Я думаю, что моя конфигурация безопасности выглядит хорошо   -  person StackQuestion    schedule 18.10.2015
comment
попробую со своей стороны через пару дней   -  person Ravindra babu    schedule 18.10.2015