I am following Spring RESTfull API tutorial. The tutorial asks to use Spring HATEOAS at some point. However, my IDE, STS, cannot find the references of the methods, linkTo and methodOn.
#GetMapping("/employees/{id}")
Resource<Employee> one(#PathVariable Long id) {
Employee emp = repository.findById(id)
.orElseThrow(() -> new EmployeeNotFoundException(id));
return new Resource<>(emp,
linkTo(methodOn(EmployeeController.class).one(id)).withSelfRel(),
linkTo(methodOn(EmployeeController.class).all()).withRel("employees")
);
}
Spring HATEOAS dependency is also here:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
The things I have tried:
Updating maven project
I am following the same tutorial and came across the same problem with the methods "linkTo" and "methodOn".
It seems like the import should be from:
import static org.springframework.hateoas.server.mvc.ControllerLinkBuilder.*;
However, it seems it is already deprecated and there is now WebMvcLinkBuilder suggested to be used:
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
I found clues in this class:
https://github.com/spring-projects/spring-hateoas-examples/blob/master/simplified/src/main/java/org/springframework/hateoas/examples/EmployeeController.java
More over, at the bottom of the tutorial page there is a link to the GitHub repo of complete project:
https://github.com/spring-guides/tut-rest
I also found problems running the "LoadDatabase.java" when following the tutorial. To fix this, I had to make it implement the CommandLineRunner and put the original code inside it's run method:
#Component
public class LoadDatabase implements CommandLineRunner {
private static final Logger log = LoggerFactory.getLogger(LoadDatabase.class);
#Override
public void run(String... args) throws Exception {
employeeRepository.save(new Employee("Bilbo", "Baggins", "burglar"));
employeeRepository.save(new Employee("Frodo", "Baggins", "thief"));
employeeRepository.findAll().forEach(employee -> log.info("Preloaded " + employee));
orderRepository.save(new Order("MacBook Pro", Status.COMPLETED));
orderRepository.save(new Order("iPhone", Status.IN_PROGRESS));
orderRepository.findAll().forEach(order -> {
log.info("Preloaded " + order);
});
}
#Autowired
EmployeeRepository employeeRepository;
#Autowired
OrderRepository orderRepository;
}
Here linkTo and methodOn are two static methods of org.springframework.hateoas.mvc.ControllerLinkBuilder class. You just need to add below two static import statements to your class:
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
OR just import ControllerLinkBuilder and use them as:
ControllerLinkBuilder.linkTo
ControllerLinkBuilder.methodOn
I used like that and it worked
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder;
#GetMapping("/employees/{id}")
EntityModel<Employee> one(#PathVariable Long id) {
Employee employee = repository.findById(id)
.orElseThrow(() -> new EmployeeNotFoundException(id));
return EntityModel.of(employee, //
WebMvcLinkBuilder.linkTo(WebMvcLinkBuilder.methodOn(EmployeeController.class).one(id)).withSelfRel(),
WebMvcLinkBuilder.linkTo(WebMvcLinkBuilder.methodOn(EmployeeController.class).all()).withRel("employees"));
}
due to fact that: ControllerLinkBuilder
is depreacted as mentioned here:
ControllerLinkBuilder java docs
WebMvcLinkBuilder should be used instead.
WebMvcLinkBuilder java docs
Consider using imports:
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
Looks like you need two imports:
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*; >>for the methodOn
import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder; >> for instatiating WebMvcLinkBuilder
Related
According to Apache Sling official site(https://sling.apache.org/documentation/bundles/apache-sling-eventing-and-job-handling.html#job-consumers), this is the way to write JobConsumer.
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.event.jobs.Job;
import org.apache.sling.event.jobs.consumer.JobConsumer;
#Component
#Service(value={JobConsumer.class})
#Property(name=JobConsumer.PROPERTY_TOPICS, value="my/special/jobtopic",)
public class MyJobConsumer implements JobConsumer {
public JobResult process(final Job job) {
// process the job and return the result
return JobResult.OK;
}
}
However #Service and #Property are both deprecated annotations.
I want to know the proper way to create JobConsumer.
Does anyone know how to write a code equivalent to the above?
The scr annotations are deprecated in AEM and it is recommended to use the official OSGi Declarative Services annotations going forward. There is a seminar by Adobe on using the OSGi R7 annotations.
The new way of writing the same would be
import org.osgi.service.component.annotations.Component;
import org.apache.sling.event.jobs.Job;
import org.apache.sling.event.jobs.consumer.JobConsumer;
#Component(
immediate = true,
service = JobConsumer.class,
property = {
JobConsumer.PROPERTY_TOPICS +"=my/special/jobtopic"
}
)
public class MyJobConsumer implements JobConsumer {
public JobResult process(final Job job) {
// process the job and return the result
return JobResult.OK;
}
}
You can refer to the below blog. I have tried to explain it here.
https://www.linkedin.com/pulse/aem-how-write-sling-jobs-aem-veena-vikraman
Given a Spring Data REST (SDR) server built with Spring Boot Gradle Plugin 2.2.5.RELEASE, is it possible to load an #Entity by self link within the server application?
I'm aware how to access it with an HTTP client, e.g. using curl:
$ curl localhost/users/1 # Responds with 200 OK and JSON representation
What I'm searching for is a mechanism to do this in the server using Java only, ideally using a standard SDR mechanism:
#Service
public class SelfLinkResolver {
public Object findBySelfLink(Link self) {
if (self == null || !self.getRel().equals(SELF)) {
throw new IllegalArgumentException("Non-null self link expected");
}
return null; // How to return the entity using a standard SDR mechanism?
}
public void exampleCall() {
Link self = new Link("localhost/users/1");
Object entity = findBySelfLink(self);
requireNonNull(entity, "Failed to load entity by self link");
}
}
An internal solution is parse your link and extract the ID (1 in your example), the call repository.findById(id).
Another solution would be new a RestTemplate, call your own API.
I finally came up with this solution, which uses SDR's UriToEntityConverter. In contrast to my question, it requires not only the self link, but also the entity class. It therefore doesn't fully answer my initial question.
I guess that there is no SDR solution that does not require the entity class, since there is no need for this within the framework, at least for usual API calls. SDR is always provided with the type information through the Repository, to which the self link refers. However, I didn't dive into other classes such as PersistentEntities, RepositoryInvokerFactory or Repositories, which might provide a solution for this.
WARNING: My tested implementation differs from this. This code is untested, but should illustrate the idea.
import lombok.NonNull;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.data.mapping.context.PersistentEntities;
import org.springframework.data.repository.support.Repositories;
import org.springframework.data.repository.support.RepositoryInvokerFactory;
import org.springframework.data.rest.core.UriToEntityConverter;
import org.springframework.hateoas.Link;
import org.springframework.stereotype.Component;
import java.net.URI;
import java.util.Optional;
import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.String.format;
import static org.springframework.hateoas.IanaLinkRelations.SELF;
#Component
public class SelfLinkToEntityConverter extends UriToEntityConverter {
private static final TypeDescriptor URI_DESCRIPTOR = TypeDescriptor.valueOf(URI.class);
SelfLinkToEntityConverter(#NonNull PersistentEntities entities,
#NonNull RepositoryInvokerFactory invokerFactory,
#NonNull Repositories repositories) {
super(entities, invokerFactory, repositories);
}
#NonNull
public <T> Optional<T> findBySelfLink(#NonNull Link self, #NonNull Class<T> entityClass) {
checkArgument(self.getRel().equals(SELF), "Non-null self link expected");
URI uri = self.expand().toUri();
TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(entityClass);
try {
#SuppressWarnings("unchecked")
T entity = (T) super.convert(uri, URI_DESCRIPTOR, typeDescriptor);
return Optional.ofNullable(entity);
} catch (IllegalArgumentException o_O) {
throw new IllegalArgumentException(format("Failed to load %s: %s",
entityClass.getSimpleName(), self.getHref()));
}
}
}
I started my first project on Spring Boot 2 (RC1). Thanks to the already good documentation this has not been to hard coming from Spring Boot 1.x.
However now that I want to integrate metrics I'm stumbeling. As far as I was able to find currently there is only documentation for the metrics shipped by default. But I'd like to also measure service level execution time as well as the time used in dynamodb.
EDIT
I'm looking for a solution using Micrometer, the library used in the new actuator library shipped with spring-boot 2.
Is there any guide on how this should be done? From this I read that there is no easy annotation based solution for arbitrary spring beans yet. Could s.o. give me an example / link to documentation on how a method like below could be metered?
#Service
#Timed
public class MyService {
public void doSomething() {
...;
}
}
#io.micrometer.core.annotation.Timed annotation seems to be out of order for custom calls due to reduction of scope, at it is mentioned in link in your question.
You need to manually setup an Aspect:
#Configuration
#EnableAspectJAutoProxy
public class AutoTimingConfiguration {
#Bean
public TimedAspect timedAspect(MeterRegistry registry) {
return new TimedAspect(registry);
}
}
This way method like this:
#Timed("GET_CARS")
public List<Car> getCars(){
return Lists.newArrayList();
}
will result in GET_CARS metric in /actuator/metrics (default) endpoint.
Here's a little sample which should get you going. There's more variants to Timer.record() which aren't shown here. (Also: Field injection only used for brevity.)
You don't have to put the called methods name into a tag. You can also make it part of the metric name itself. Just wanted to show what you could do.
Update 2018-03-12: As of Micrometer 1.0.0 a TimedAspect has been introduced so that you can also use the #Timed annotation. For now you need to register the Bean yourself. (You need to be cautious though when you have custom #Timed annotations on your Spring-MVC or Jersey resources.) This was already mentioned by Michal Stepan in a follow-up answer.
package io.github.mweirauch.micrometered.eval;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import io.micrometer.core.annotation.Timed;
import io.micrometer.core.aop.TimedAspect;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import io.micrometer.core.instrument.Timer.Sample;
#Configuration
#EnableAspectJAutoProxy
public class TimingStuff {
#Service
static class MyService {
#Autowired
private MeterRegistry registry;
public void helloManual() {
// you can keep a ref to this; ok to call multiple times, though
Timer timer = Timer.builder("myservice").tag("method", "manual").register(registry);
// manually do the timing calculation
long start = System.nanoTime();
doSomething();
timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS);
}
public void helloSupplier() {
Timer timer = Timer.builder("myservice").tag("method", "supplier").register(registry);
// execution of the method is timed internally
timer.record(() -> doSomething());
}
public void helloSample() {
Timer timer = Timer.builder("myservice").tag("method", "sample").register(registry);
// records time taken between Sample creation and registering the
// stop() with the given Timer
Sample sample = Timer.start(registry);
doSomething();
sample.stop(timer);
}
// TimedAspect adds "class" and "method" tags
#Timed(value = "myservice.aspect")
public void helloAspect() {
doSomething();
}
private void doSomething() {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
//
}
}
}
#Autowired
private MyService myService;
#Bean
TimedAspect timedAspect(MeterRegistry registry) {
return new TimedAspect(registry);
}
#Scheduled(fixedRate = 1000)
public void postConstruct() {
myService.helloManual();
myService.helloSupplier();
myService.helloSample();
myService.helloAspect();
}
}
In case you go for Prometheus, you'd end up with something like that:
# HELP myservice_seconds
# TYPE myservice_seconds summary
myservice_seconds_count{application="micrometered",method="manual",} 4.0
myservice_seconds_sum{application="micrometered",method="manual",} 0.200378014
myservice_seconds_max{application="micrometered",method="manual",} 0.050115291
myservice_seconds_count{application="micrometered",method="supplier",} 4.0
myservice_seconds_sum{application="micrometered",method="supplier",} 0.200393455
myservice_seconds_max{application="micrometered",method="supplier",} 0.05011635
myservice_seconds_count{application="micrometered",method="sample",} 4.0
myservice_seconds_sum{application="micrometered",method="sample",} 0.200527005
myservice_seconds_max{application="micrometered",method="sample",} 0.050250191
# HELP myservice_aspect_seconds
# TYPE myservice_aspect_seconds summary
myservice_aspect_seconds_count{application="micrometered",class="io.github.mweirauch.micrometered.eval.TimingStuff$MyService",method="helloAspect",} 4.0
myservice_aspect_seconds_sum{application="micrometered",class="io.github.mweirauch.micrometered.eval.TimingStuff$MyService",method="helloAspect",} 0.201824272
myservice_aspect_seconds_max{application="micrometered",class="io.github.mweirauch.micrometered.eval.TimingStuff$MyService",method="helloAspect",} 0.051014296
I'm building a plugin for Jira. I want to add a caching-layer so I wanted to use the com.atlassian.cache.CacheManager. I have to inject this via an argument / setter.
Since I'm extending an other class I wanted to inject this via a setter, but for some reason it returns null all the time.
import com.atlassian.cache.Cache;
import com.atlassian.cache.CacheLoader;
import com.atlassian.cache.CacheManager;
import com.atlassian.cache.CacheSettingsBuilder;
public class Foo extends AbstractJiraContextProvider
{
private CacheManager cacheManager;
public void setCacheManager(CacheManager cacheManager) {
//It does not get past this function..
this.cacheManager = cacheManager;
}
#Override
public Map getContextMap(ApplicationUser user, JiraHelper jiraHelper) {
cache = this.cacheManager.getCache("bar");
}
}
I also tried this by doing the following:
public Foo(CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
After that the plugin does nothing anymore. I do not get errors, but it just gives 0 output.
I used this for documentation: https://developer.atlassian.com/confdev/confluence-plugin-guide/writing-confluence-plugins/accessing-confluence-components-from-plugin-modules
And https://developer.atlassian.com/confdev/development-resources/confluence-developer-faq/how-do-i-cache-data-in-a-plugin#HowdoIcachedatainaplugin?-Instructions
Your question mentions JIRA, but the documentation links that you provide are for Confluence (and outdated).
If you're developing an add-on for a recent version of JIRA (7.2+) then injecting components is now handled by Atlassian Spring Scanner 2, so everything works with annotations.
If you follow the instructions listed here then you should be able to inject components via a constructor like so:
#Component
public class MyService {
private final IssueService issueService;
private final InternalComponent internalComponent;
#Inject
public MyService(#ComponentImport final IssueService issueService,final InternalComponent internalComponent) {
this.issueService = issueService;
this.internalComponent = internalComponent;
}
}
I just downloaded the play framework from their site and am working through this tutorial.
I've noticed the framework creates the folders app/controllers and app/views, but not a models folder. I created it manually and added Task.java to it. When I get to the section entitled "Rendering the first page" and open localhost:9000/tasks I get a compilation error that says package play.models does not exist. Here is what my Task.java looks like:
package models;
import java.util.*;
public class Task {
public Long id;
#Required
public String label;
public static List<Task> all() {
return new ArrayList<Task>();
}
public static void create(Task task) {
}
public static void delete(Long id) {
}
}
Here is application.java, the file generating the compilation error:
package controllers;
import play.*;
import play.mvc.*;
import views.html.*;
import play.data.*;
import play.models.*; // COMPILATION ERROR: "package play.models does not exist"!
public class Application extends Controller {
static Form<Task> taskForm = Form.form(Task.class);
public static Result index() {
//return ok(index.render("Your new application is ready."));
return redirect(routes.Application.tasks());
}
public static Result tasks() {
return ok(views.html.index.render(Task.all(), taskForm));
}
public static Result newTask() {
return TODO;
}
public static Result deleteTask(Long id) {
return TODO;
}
}
I believe it's supposed to be import models.Task; as opposed to import play.models.*;
That's quite confusing (IMHO) step in this tutorial, instead scroll down to Persist the tasks in a database section which describes preparing a model to cooperate with DB :) (it extends Model class, uses proper annotations, etc)
As you recognized it yet, you need to create a models package yourself.
Also as cYn wrote: you should import models like models.SomeModel into your controller
You are correct HukeLau_DABA , the Play will not create the models package for you. you have to create it.
I got these imports in my Application controller class. I got this sample play application running.
import play.api._
import play.api.mvc._
import play.api.data.Form
import play.api.data.Forms._
import models.Task
and another thing in Eclipse is it will not import the necessary imports automatically.
it is bit pain now, once the IDE support get better I hope this will change.