I'm using Spring version 2.1.18.RELEASE (I can't change this version)
I need to implement a crud repository for elasticsearch, for this I connect spring-data-elasticsearch (version 3.1.21.RELEASE is automatically pulled up) with elasticsearch 6.4.3
I tried a bunch of manuals, but elastic is so different from version to version that I can't find a solution. I need to connect to remote server via https with username and password.
pom:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
</dependency>
Config:
#Configuration
#EnableElasticsearchRepositories(basePackages = "path.to.elastic")
#ComponentScan(basePackages = {"path.to.elastic"})
public class ElasticConfiguration {
private final int port = 1234;
#Bean
public Client client() throws Exception {
Settings settings = Settings.builder().put("cluster.name", "test")
.put("xpack.security.user", "login:pass")
.put("xpack.security.transport.ssl.enabled", "true")
.put("xpack.security.transport.ssl.enabled", "true")
.build();
return new PreBuiltTransportClient(settings)
.addTransportAddress(new TransportAddress(InetAddress.getByName("bah.elk1.com"), port))
.addTransportAddress(new TransportAddress(InetAddress.getByName("bah.elk2.com"), port))
.addTransportAddress(new TransportAddress(InetAddress.getByName("bah.elk3.com"), port));
}
#Bean
public ElasticsearchOperations elasticsearchTemplate() throws Exception {
return new ElasticsearchTemplate(client());
}
}
Repository:
#Repository
public interface ElkThingRepository extends ElasticsearchRepository<Things, Long> {
List<Things> findByEarNameAndName(String earName, String thingName);
}
Service interface:
public interface ElkThingsService {
List<Things> simpleGet(String thingName);
}
Service impl:
#Service
public class ElkThingsServiceImpl implements ElkThingsService {
private final ElkThingsRepository elkThingsRepository;
#Autowired
public ElkThingsServiceImpl(ElkThingsRepository elkThingsRepository) {
this.elkThingsRepository = elkThingsRepository;
}
public List<Things> simpleGet(String thingsName) {
return elkThingsRepository.findByEarNameAndName(AppInfo.SUBSYSTEM_CODE, thingName);
}
}
Things:
#Data
#Document(indexName = "things-*", type = "things")
public class Things {
#Id
private Long id;
private String earName;
private String name;
}
Now im get exceprion:
java.lang.IllegalArgumentException: unknown setting [xpack.security.user] please check that any required plugins are installed, or check the breaking changes documentation for removed settings
When i add spring-data-elasticsearch 4.0.0 and try to use RestHighLevelClient i get NoClassDefFoundError error creating RestHighLevelClient bean
I am working on a java project that runs in Azure Functions. The problem is that I can't make the Java CDI 2.0 work in the application.
Please refer to the application codes below.
Function.java
public class Function {
#Inject
private Util util;
/**
* This function listens at endpoint "/api/HttpTrigger-Java". Two ways to invoke it using "curl" command in bash:
* 1. curl -d "HTTP Body" {your host}/api/HttpTrigger-Java&code={your function key}
* 2. curl "{your host}/api/HttpTrigger-Java?name=HTTP%20Query&code={your function key}"
* Function Key is not needed when running locally, to invoke HttpTrigger deployed to Azure, see here(https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-http-webhook#authorization-keys) on how to get function key for your app.
*/
#FunctionName("HttpTrigger-Java")
public HttpResponseMessage run(
#HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.FUNCTION) HttpRequestMessage<Optional<String>> request,
final ExecutionContext context) {
context.getLogger().info("Java HTTP trigger processed a request.");
// Parse query parameter
String query = request.getQueryParameters().get("name");
String name = request.getBody().orElse(query);
util.display();
if (name == null) {
return request.createResponseBuilder(HttpStatus.BAD_REQUEST).body("Please pass a name on the query string or in the request body").build();
} else {
return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build();
}
}
}
Util.java
#RequestScoped
public class Util {
public void display(){
System.out.println("testing..");
}
}
I have this in my pom.xml
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
when I deploy this and hit the endpoint, I am getting an nullpointerexception when accessing the method from the injected bean..
Can someone enlighten me regarding this matter?
The rest API is failing with 400 Bad request with below response
javax.xml.bind.JAXBException
- with linked exception: [org.codehaus.jettison.json.JSONException: A JSONObject text must begin with '{' at character 0 of ]
Below is my code,
API Resource
#GET
#Path("/getTeams")
#Produces(MediaType.APPLICATION_JSON)
public Response getTeamList(final TeamSearchRequest teamSearchRequest, #Context UriInfo uriInfo) {
//Business
}
Request Class
#XmlRootElement(name = "teamSearchRequest")
public class TeamSearchRequest {
private String searchText;
private String searcherTeamId;
public TeamSearchRequest(){}
//setters and getters
}
API URI - http://localhost:8080/letsplay/team/getTeams
API Request Body -
{
"teamSearchRequest": {
"searchText": "Mumbai",
"searcherTeamId": "1"
}
}
Note - I have already checked all the similar questions in SO.
Any suggestions is most appreciated.
I think your JSON is wrong. It should look like this:
{
"searchText": "Mumbai",
"searcherTeamId": "1"
}
Unable to load class 'javax.xml.bind.JAXBException'.
File | Settings | Build, Execution, Deployment | Build Tools | Gradle
Change gradle JDK
I have been writing some simple unit testing routines for a simple spring web application. When I add #JsonIgnore annotation on a getter method of a resource, the resulting json object does not include the corresponding json element. So when my unit test routine tries to test if this is null (which is the expected behavior for my case, I don't want the password to be available in json object), test routine runs into an exception:
java.lang.AssertionError: No value for JSON path: $.password, exception: No results for path: $['password']
This is the unit test method I wrote, testing the 'password' field with is(nullValue()) method:
#Test
public void getUserThatExists() throws Exception {
User user = new User();
user.setId(1L);
user.setUsername("zobayer");
user.setPassword("123456");
when(userService.getUserById(1L)).thenReturn(user);
mockMvc.perform(get("/users/1"))
.andExpect(jsonPath("$.username", is(user.getUsername())))
.andExpect(jsonPath("$.password", is(nullValue())))
.andExpect(jsonPath("$.links[*].href", hasItem(endsWith("/users/1"))))
.andExpect(status().isOk())
.andDo(print());
}
I have also tried it with jsonPath().exists() which gets a similar exception stating that the path doesn't exist. I am sharing some more code snippets so that the whole situation becomes more readable.
The controller method I am testing looks something like this:
#RequestMapping(value="/users/{userId}", method= RequestMethod.GET)
public ResponseEntity<UserResource> getUser(#PathVariable Long userId) {
logger.info("Request arrived for getUser() with params {}", userId);
User user = userService.getUserById(userId);
if(user != null) {
UserResource userResource = new UserResourceAsm().toResource(user);
return new ResponseEntity<>(userResource, HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
I am using spring hateos resource assembler for converting entity to resource objects and this is my resource class:
public class UserResource extends ResourceSupport {
private Long userId;
private String username;
private String password;
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
#JsonIgnore
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
I understand why this is getting an exception, also in a way, the test is successful that it could not find the password field. But what I want to do is, run this test to ensure that the field is not present, or if present, it contains null value. How can I achieve this?
There is a similar post in stack overflow:
Hamcrest with MockMvc: check that key exists but value may be null
In my case, the field may be non existent as well.
For the record, these are the versions of test packages I am using:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path-assert</artifactId>
<version>2.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
[EDIT]
To be more precise, say, you have to write a test for an entity where you know some of the fields need to be null or empty or should not even exists, and you don't actually go through the code to see if there is a JsonIgnore added on top of the property. And you want your tests to pass, how can I do this.
Please feel free to tell me that this is not practical at all, but still would be nice to know.
[EDIT]
The above test succeeds with the following older json-path dependencies:
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>0.9.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path-assert</artifactId>
<version>0.9.1</version>
<scope>test</scope>
</dependency>
[EDIT] Found a quickfix that works with latest version of jayway.jasonpath after reading the documentation of spring's json path matcher.
.andExpect(jsonPath("$.password").doesNotExist())
I had the same problem with the newer version. It looks to me that the doesNotExist() function will verify that the key is not in the result:
.andExpect(jsonPath("$.password").doesNotExist())
There is a difference between the property that is present, but having null value, and the property not being present at all.
If the test should fail only when there is a non-null value, use:
.andExpect(jsonPath("password").doesNotExist())
If the test should fail as soon as the property is present, even with a null value, use:
.andExpect(jsonPath("password").doesNotHaveJsonPath())
#JsonIgnore is behaving as expected, not producing the password in the json output, so how could you expect to test something that you are explicitly excluding from the output?
The line:
.andExpect(jsonPath("$.property", is("some value")));
or even a test that the property is null:
.andExpect(jsonPath("$.property").value(IsNull.nullValue()));
correspond to a json like:
{
...
"property": "some value",
...
}
where the important part is the left side, that is the existence of "property":
Instead, #JsonIgnore is not producing the porperty in the output at all, so you can't expect it not in the test nor in the production output.
If you don't want the property in the output, it's fine, but you can't expect it in test.
If you want it empty in output (both in prod and test) you want to create a static Mapper method in the middle that is not passing the value of the property to the json object:
Mapper.mapPersonToRest(User user) {//exclude the password}
and then your method would be:
#RequestMapping(value="/users/{userId}", method= RequestMethod.GET)
public ResponseEntity<UserResource> getUser(#PathVariable Long userId) {
logger.info("Request arrived for getUser() with params {}", userId);
User user = Mapper.mapPersonToRest(userService.getUserById(userId));
if(user != null) {
UserResource userResource = new UserResourceAsm().toResource(user);
return new ResponseEntity<>(userResource, HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
At this point, if your expectations are for Mapper.mapPersonToRest to return a user with a null password, you can write a normal Unit test on this method.
P.S. Of course the password is crypted on the DB, right? ;)
doesNotHaveJsonPath for checking that it is not in json body
I wanted to reuse the same code I use for testing for the parameter being supplied, and for it missing, and this is what I came up with
#Test
void testEditionFoundInRequest() throws JsonProcessingException {
testEditionWithValue("myEdition");
}
#Test
void testEditionNotFoundInRequest() {
try {
testEditionWithValue(null);
throw new RuntimeException("Shouldn't pass");
} catch (AssertionError | JsonProcessingException e) {
var msg = e.getMessage();
assertTrue(msg.contains("No value at JSON path"));
}
}
void testEditionWithValue(String edition) {
var HOST ="fakeHost";
var restTemplate = new RestTemplate();
var myRestClientUsingRestTemplate = new MyRestClientUsingRestTemplate(HOST, restTemplate);
MockRestServiceServer mockServer;
ObjectMapper objectMapper = new ObjectMapper();
String id = "userId";
var mockResponse = "{}";
var request = new MyRequest.Builder(id).edition(null).build();
mockServer = MockRestServiceServer.bindTo(restTemplate).bufferContent().build();
mockServer
.expect(method(POST))
// THIS IS THE LINE I'd like to say "NOT" found
.andExpect(jsonPath("$.edition").value(edition))
.andRespond(withSuccess(mockResponse, APPLICATION_JSON));
var response = myRestClientUsingRestTemplate.makeRestCall(request);
} catch (AssertionError | JsonProcessingException e) {
var msg = e.getMessage();
assertTrue(msg.contains("No value at JSON path"));
}
When trying a POST-Request using jersey 1.18, I get the following exception:
Exception in thread "main" java.lang.AbstractMethodError: javax.ws.rs.core.Response.getStatusInfo()Ljavax/ws/rs/core/Response$StatusType;
at javax.ws.rs.WebApplicationException.computeExceptionMessage(WebApplicationException.java:205)
at javax.ws.rs.WebApplicationException.<init>(WebApplicationException.java:179)
at javax.ws.rs.WebApplicationException.<init>(WebApplicationException.java:244)
at com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider.writeTo(AbstractRootElementProvider.java:159)
at com.sun.jersey.api.client.RequestWriter.writeRequestEntity(RequestWriter.java:300)
at com.sun.jersey.client.urlconnection.URLConnectionClientHandler._invoke(URLConnectionClientHandler.java:217)
at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:153)
at com.sun.jersey.api.client.Client.handle(Client.java:652)
at com.sun.jersey.api.client.WebResource.voidHandle(WebResource.java:706)
at com.sun.jersey.api.client.WebResource.access$400(WebResource.java:74)
at com.sun.jersey.api.client.WebResource$Builder.post(WebResource.java:555)
at jtmt.shell.commands.upld.TrcUploader.upload(TrcUploader.java:29)
at jtmt.shell.commands.trcrt.ICMPTraceRoute.run(ICMPTraceRoute.java:92)
at jtmt.shell.commands.Main.<init>(Main.java:42)
at jtmt.shell.commands.Main.main(Main.java:64)
The code that produces this is:
Trace trc = Trace.fromTracerouteResult(trace);
WebResource wr = _c.resource(URL);
WebResource.Builder wrb = wr.cookie(new Cookie("user", USER));
wrb = wrb.cookie(new Cookie("auth", AUTH));
wrb.post(trc);
return true;
The entiry Trace looks like this:
#XmlRootElement
public class Trace {
private Map<Integer,List<String>> addressesPerHop;
private String source;
private String traget;
/* getters and setters */
}
I include the following jars when compiling and executing:
commons-cli-1.2.jar
jersey-server-1.18.jar
asm-3.1.jar
jersey-servlet-1.18.jar
jersey-client-1.18.jar
jersey-core-1.18.jar
Any Ideas whats missing?
Short answer: Your version of Jersey is too old. The method javax.ws.rs.core.Response.getStatusInfo() is part of the 2.0 JAX-RS spec. See: https://jax-rs-spec.java.net/nonav/2.0-SNAPSHOT/apidocs/javax/ws/rs/core/Response.html#getStatusInfo().
Jersey 2.0 appears to be the first version that supports JAX-RS 2.0.