As we know, every entity of ElasticsearchEntityMapper requires annotation
#Document(indexName="foo")
public class Foo {...}
, so that we can use convenient methods, like:
<T> Page<T> queryForPage(SearchQuery query, Foo.class);
But it is very common, that the indices of elasticsearch were designed time-based or language-based. i.e.
#Document(indexName="2019")
public class Foo {...}
#Document(indexName="2020")
public class Foo {...}
or
#Document(indexName="english")
public class Foo {...}
#Document(indexName="german")
public class Foo {...}
Of course, we can't create classes like this, one class with different indices.
What should we do in this case? One class each index, Foo2019, Foo2020? <- Very bad idea.
I am wondering, why does spring-data-elasticsearch design entity in this way? It's not really flexible. Or I misunderstand the usage?
Thanks for your help in advance! :)
You are right in that using this with fix Strings is not flexible.
But you can also use a SpEL Expression for the index name. And when using the ElasticsearchOperations methods and not the repository methods, you can pass in the name of the index, this is overriding the name defined in the #Documentannotation.
Related
I'm having some trouble implementing a function over some pre-existing code.
Other programmers working on this project previously defined a genric abstract "restcontroller" (it's not actually annotated as #RestController but it's meant to be extended by classes with that annotation)
public abstract class AbstractController<T extends AbstractEntity, R extends JpaRepository<T, Integer>> {
#GetMapping(value = "/getall")
public Paging<T> getAll(#RequestParam Integer itemsPerPage,
#RequestParam Integer pageIndex,
#RequestParam Map<String, String> filters,
#Autowired Consumer consumer) {
//Fetch entities of type T from repository R and return them
}
//other generic crud operations
}
This class is usually extended by concrete controllers that simply define other operations on their specific types, but do no alter generic crud operations.
What I want to do is extend this class, but override the getAll method, like this:
#RestController
#RequestMapping("/api/tasks")
public class TaskController extends AbstractController<Task, TaskRepository> {
#Override
public Paging<Task> getAll(Integer itemsPerPage, Integer pageIndex, Map<String, String> filters, Consumer consumer) {
LoggerFactory.getLogger(LazyTaskController.class).log("function called successfully!");
Paging<Task> paging = super.getAll(itemsPerPage, pageIndex, filters, consumer);
//do things with return value before returning
return paging;
}
}
If I call BASEURL/api/tasks/getall?itemsPerPage=25&pageIndex=0 without overriding the getAll method, the parameters are wired correctly (the Map contains two values, itemsPerPage and pageIndex, as expected, and consumer contains a concrete implementation of the intercace Consumer).
However if I do override it, the Map for some reason contains two values, one with key "consumer" and type Proxy, and another with key "org.springframework.validation.BindingResult.consumer" and value of type BeanPropertyBindingResult; and consumer contains a Proxy.
I suppose the #Override interferes with the autowiring of Consumer, but I can't figure out how to properly achieve what I have in mind (manipulating the results of getAll before returning them).
Thank you in advance
Nevermind, I solved it.
The problem with the Map was solved by adding #RequestParam and #Autowired annotations to the overridden method parameters as well.
The problem with the Consumer concrete type was somehow solved by applying a custom annotation that I found on another class in the codebase, I'm still not sure about what that annotation does but at least I know what to look for now.
I was playing with the following question: Using Java 8's Optional with Stream::flatMap and wanted to add a method to a custom Optional<T> and then check if it worked.
More precise, I wanted to add a stream() to my CustomOptional<T> that returns an empty stream if no value is present, or a stream with a single element if it is present.
However, I came to the conclusion that Optional<T> is declared as final.
Why is this so? There are loads of classes that are not declared as final, and I personally do not see a reason here to declare Optional<T> final.
As a second question, why can not all methods be final, if the worry is that they would be overridden, and leave the class non-final?
According to this page of the Java SE 8 API docs, Optional<T> is a value based class. According to this page of the API docs, value-based classes have to be immutable.
Declaring all the methods in Optional<T> as final will prevent the methods from being overridden, but that will not prevent an extending class from adding fields and methods. Extending the class and adding a field together with a method that changes the value of that field would make that subclass mutable and hence would allow the creation of a mutable Optional<T>. The following is an example of such a subclass that could be created if Optional<T> would not be declared final.
//Example created by #assylias
public class Sub<T> extends Optional<T> {
private T t;
public void set(T t) {
this.t = t;
}
}
Declaring Optional<T> final prevents the creation of subclasses like the one above and hence guarantees Optional<T> to be always immutable.
As others have stated Optional is a value based class and since it is a value based class it should be immutable which needs it to be final.
But we missed the point for this. One of the main reason why value based classes are immutable is to guarantee thread safety. Making it immutable makes it thread safe. Take for eg String or primitive wrappers like Integer or Float. They are declared final for similar reasons.
Probably, the reason is the same as why String is final; that is, so that all users of the Optional class can be assured that the methods on the instance they receive keep to their contract of always returning the same value.
Though we could not extend the Optional class, we could create our own wrapper class.
public final class Opt {
private Opt() {
}
public static final <T> Stream<T> filledOrEmpty(T t) {
return Optional.ofNullable(t).isPresent() ? Stream.of(t) : Stream.empty();
}
}
Hope it might helps you. Glad to see the reaction!
There are a lot of examples online of using QueryDSL like this:
public class CustomerRepositoryImpl
extends QueryDslRepositorySupport
implements CustomerRepositoryCustom {
public Iterable<Customer> findAllLongtermCustomersWithBirthday() {
QCustomer customer = QCustomer.customer;
return from(customer)
.where(hasBirthday().and(isLongTermCustomer()))
.list(customer);
}
}
This code makes sense, but I am wondering why customer is "duplicated" in the method call to list().
Shouldn't the type be obvious from the reference in from(customer)?
from defines the source and list the projection. Querydsl query classes don't have any generic type argument for the return type, the projection (select part) is defined in the last part of the query construction chain.
Examples for cases where a different projection than the source is wanted
specific columns only: query.list(customer.firstName, customer.lastName)
constructor invocation : Projections.constructor(...)
Bean population: Projections.bean(...)
multiple from calls are used
As Bloch states in Item 3 ("Enforce the singleton property with a private constructor or an enum type") of Effective Java 2nd Edition, a single-element enum type is the best way to implement a singleton. Unfortunately the old private constructor pattern is still very widespread and entrenched, to the point that many developers don't understand what I'm doing when I create enum singletons.
A simple // Enum Singleton comment above the class declaration helps, but it still leaves open the possibility that another programmer could come along later and add a second constant to the enum, breaking the singleton property. For all the problems that the private constructor approach has, in my opinion it is somewhat more self-documenting than an enum singleton.
I think what I need is an annotation which both states that the enum type is a singleton and ensures at compile-time that only one constant is ever added to the enum. Something like this:
#EnumSingleton // Annotation complains if > 1 enum element on EnumSingleton
public enum EnumSingleton {
INSTANCE;
}
Has anyone run across such an annotation for standard Java in public libraries anywhere? Or is what I'm asking for impossible under Java's current annotation system?
UPDATE
One workaround I'm using, at least until I decide to actually bother with rolling my own annotations, is to put #SuppressWarnings("UnusedDeclaration") directly in front of the INSTANCE field. It does a decent job of making the code look distinct from a straightforward enum type.
You can use something like this -
public class SingletonClass {
private SingletonClass() {
// block external instantiation
}
public static enum SingletonFactory {
INSTANCE {
public SingletonClass getInstance() {
return instance;
}
};
private static SingletonClass instance = new SingletonClass();
private SingletonFactory() {
}
public abstract SingletonClass getInstance();
}
}
And you can access in some other class as -
SingletonClass.SingletonFactory.INSTANCE.getInstance();
I'm not aware of such an annotation in public java libraries, but you can define yourself such a compile time annotation to be used for your projects. Of course, you need to write an annotation processor for it and invoke somehow APT (with ant or maven) to check your #EnumSingleton annoted enums at compile time for the intended structure.
Here is a resource on how to write and use compile time annotations.
Given the following class structure:
#MappedSuperclass
#Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public abstract class Animal {}
#Entity
public class Dog {}
#Entity
public class Cat {}
With Spring Data JPA, is it possible to use a generic Animal Repository to persist an Animal at runtime without knowing which kind of Animal it is?
I know I can do it using a Repository-per-entity and by using instanceof like this:
if (thisAnimal instanceof Dog)
dogRepository.save(thisAnimal);
else if (thisAnimal instanceof Cat)
catRepository.save(thisAnimal);
}
but I don't want to resort to the bad practice of using instanceof.
I've tried using a generic Repository like this:
public interface AnimalRepository extends JpaRepository<Animal, Long> {}
But this results in this Exception: Not an managed type: class Animal. I'm guessing because Animal is not an Entity, it's a MappedSuperclass.
What's the best solution?
BTW - Animal is listed with the rest off my classes in persistence.xml, so that's not the problem.
Actually the problem is with your mapping. You either use #MappedSuperclass or #Inheritance. Both together don't make sense. Change your entity to:
#Entity
#Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public abstract class Animal {}
Don't worry, the underlying database scheme is the same. Now one, general AnimalRepository will work. Hibernate will do the introspection and find out which table to use for an actual subtype.