Could I pass annotation to child class which extends it? - java

I'm lazy person... i just want the simplest way, now i'm learning android room. This might be answered here "Why is it not possible to extend annotations in Java?", but it seems like to try pass annotation to another annotation, right? So, Could i pass annotation to the child class for example, here is my parent class 'Model':
#Entity
public abstract class Model implements Parcelable{
#Nullable
#PrimaryKey
private Object id;
public String toJSON(){
return new Gson().toJson(this);
}
public <T> T getId(Class<T>type) {
if(type.equals(Integer.class)||type.equals(int.class)) {
return (T) Integer.valueOf(new Double(Double.parseDouble(String.valueOf(id))).intValue());
}
else if(type.equals(Long.class)||type.equals(long.class)) {
return (T) Long.valueOf(new Double(Double.parseDouble(String.valueOf(id))).longValue());
}
else if(type.equals(Double.class)||type.equals(double.class)) {
return (T) Double.valueOf(id.toString());
}else if(type.equals(UUID.class)){
return (T) UUID.fromString(String.valueOf(id));
}
return type.cast(id);
}
public <T> void setId(T id) {
this.id = id;
}
}
I tried to pass #Entity to child class.
public class Movie extends Model {
public static final String IDENTIFIER = Movie.class.getSimpleName();
#SerializedName("popularity")
private double popularity;
#SerializedName("vote_count")
private long voteCount;
#SerializedName("video")
private boolean video;
}
Because my data access object cannot detect my 'Movie' class, except i'm added Entity annotation
#Dao
public interface FavMovieDAO {
#Query("SELECT * FROM Movie WHERE id = :movieId")
public Movie find (int movieId);
}
If there is no way, i'll declare my entire model class as an Entity... :/. Thanks in advance.

Related

downcast to subclass and get subclass only fields

I have classes similar to DataRequest & DataWithIdRequest. DataWithIdRequest gets passed into my controller method. I want to pass the subclass object ONLY to another class for processing. However, when I try to downcast to DataRequest the extra field is still showing. How can I accomplish this?
public class DataRequest {
private String name;
public String getName() {
return name;
}
public void setFirstName(String name) {
this.name = name;
}
}
public class DataWithIdRequest extends DataRequest {
private Integer id;
public Integer getId() {
return contractKey;
}
public void setContractKey(Integer id) {
this.id = id;
}
}
//controller
processData(request);
}
//domain class
public Boolean processData(DataRequest request) {
//request here has DataWithIdRequest field
//but I only want the subclass
}
public Boolean processData(DataRequest request) { }
Because in your method processData, request's type is DataRequest. You want it to be DataWithIdRequest.
public Boolean processData(DataWithIdRequestrequest request) { }
You can only offer a part of an API (application programmer's interface), by separating the code in an interface.
public interface Identified {
Integer getId();
public void setContractKey(Integer id);
}
public class DataWithIdRequest extends DataRequest implements Identified {
private Integer id;
#Override
public Integer getId() {
return contractKey;
}
#Override
public void setContractKey(Integer id) {
this.id = id;
}
}
public Boolean processData(DataRequest request) {
if (request instanceOf Identified identified) {
identified.setContractKey(13);
}
}
Or move the problem to the caller:
public Boolean processData(Identified request) {
request.setContractKey(13);
}
By the way it more usual to use int, boolean, the primitive types.
To hide the information completely, you need to create a new instance of DataRequest by DataWithIdRequest (that's why mapping library like mapstruct is useful), but not directly passing it.
Explanation:
This is how inheritance works, imagine a method takes a parameter of an interface or abstract class, by using instanceof inside the method we can check the object actual type and do something specific. e.g.
public void drawShape(Shape shape) {
if (shape instanceof Circle) {
Circle circle = (Circle) shape;
// do sth
} else if (shape instanceof Square) {
// do sth else
}
}
The above example is completely valid (although not a good programming style, that's another story).
The object inside the memory holds all the actual class details, passing it to a method doesn't change anything to the memory. The parameter (e.g. shape) is only another reference to the same memory location.
Maybe I don't understand the question fully but: as you want I it's not possible since:
public class DataWithIdRequest extends DataRequest
means DataRequest is a subset of DataWithIdRequest, it's an intersection.
You unfortunately need to find an other way

Spring Boot Custom Query In Controller

How do i add a custom query to my Spring boot application and access it in the controller?
I have two tables called CarBrand and YearMade. CarBrand has ID, code and Brand as columns. YearMade also has ID, code and year as columns.
I have written my model classes with setter and getter methods for each entity. I have added my repository interfaces and my service classes.
public interface YearRepository extends JpaRepository<Year, Long> {
}
My Brand Repository
public interface BrandRepository extends JpaRepository<Brand, Long> {
#Query("select b from brand b where brand.brand = ?1")
List<Brand> findVehicleBrand(String brand);
}
Here is my service class
public class YearService {
#Autowired
private YearRepository yearRepository;
public List<Year> listAll(){
return yearRepository.findAll();
}
public void save(Year engineSize){
yearRepository.save(engineSize);
}
public Year get (long id){
return yearRepository.findById(id).get();
}
public void delete (Long id){
yearRepository.deleteById(id);
}
}
My Brand Service
public interface BService {
List<Brand> findVehicleBrand(String name);
}
And this.
#Service
#Transactional
public class BrandService implements BService{
#Autowired
private BrandRepository brandRepository;
public List<Brand> listAll(){
return brandRepository.findAll();
}
public void save(Brand brand){
brandRepository.save(brand);
}
public Brand get (long id){
return brandRepository.findById(id).get();
}
public void delete (Long id){
brandRepository.deleteById(id);
}
#Override
public List<Brand> findVehicleBrand(String name) {
var brand = (List<Brand>) brandRepository.findVehicleBrand(name);
return brand;
}
}
In my controller, I get a path variable with a string, i use substring to break the string into two. The two substrings have the code for brand and year. The first two represent the year and the other three represent the brand. How do i compare the codes to the codes in the database to get the actual year and brand.
http://localhost:8081/vincode/wwQPT
The ww is the code for the year 1990 and QPT is for Honda Motor Company in the database.
I want a JSON response like this
{
Year Made : 1990,
Brand Name : Honda Motor Company
}
Here is the controller class i have so far.
#RequestMapping("/{vincode}")
public #ResponseBody String getAttr(#PathVariable(value="vincode") String vincode) {
String yr = vincode.substring(0,1);
String brand = vincode.substring(2,4);
System.out.println(yr);
return yr;
}
Where do i add the query and how do i use it in my controller?
Thank you.
If you dont have request mappong wlth value top of the class then http://localhost:8081/vincode/ww/QPT
RequestMapping("/vincode/{code}/{company}") can be more useful
There is no need to use substring maybe code or company key sizes changes.
Also service layer can be injected and used anytime.
Firstly add this statement in BrandRepository interface :
public interface BrandRepository extends JpaRepository<Brand, Long> {
#Query("select b from brand b where brand.brand = ?1")
List<Brand> findVehicleBrand(String brand);
public Brand findByCode(String code);
}
In YearRepository interface :
public interface YearRepository extends JpaRepository<Year, Long> {
public Year findByCode(String code);
}
Then add this method in BrandService Class:
public String findByCode (String code){
return brandRepository.findByCode(code).getBrand();
}
Then add this method in YearService Class:
public String findByCode (String code){
return yearRepository.findByCode(code).getYear;
}
Create Domain Class :
public class YearBrand
{
private String YearMade;
private String BrandName;
public YearBrand(String year, String brand)
{
this.YearMade=year;
this.BrandName=brand;
}
}
Then In Controller Class :
#RequestMapping("/{vincode}")
public YearBrand getAttr(#PathVariable(value="vincode") String vincode) {
String yr = vincode.substring(0,1);
String brand = vincode.substring(2,4);
return new YearBrand(yearService.findByCode(yr),brandService.findByCode(brand));
}
NOTES:
Make sure your Controller Class is annotated with #RestController
Spring Data JPA derives queries based on method naming conventions.
So, to get year by code in YearMade table, you need to modify your YearReporsitory interface like this (add an abstract method):
public interface YearRepository extends JpaRepository<Year, Long> {
// set return type as required
//find - Do What, ByCode - Criteria.
public Integer findByCode(String code);
}
And, use this method in your YearService just as you've used other methods.
But, you cannot use the same method for getting brand by code requirement. You'll have to write a repo class for it like:
public interface BrandRepository extends JpaRepository<CarBrand, Long> {
public Integer findByCode(String code);
}
You can write these methods for all the members of your Entity class. You've to follow the naming convention to get Spring recognize it.
EDIT (to show how to use this in controller and service class):
YearRepository interface:
public interface YearRepository extends JpaRepository<Year, Long> {
// set return type as required
//find - Do What, ByCode - Criteria.
public Integer findByCode(String code);
}
BrandRepository
public interface BrandRepository extends JpaRepository<Brand, Long> {
/*The below two methods are abstract methods.*/
// it must follow the findby<MemberName> convention
//return CarBrand
CarBrand findByBrand(String brand);
/*return a CarBrand Entity*/
public CarBrand findByCode(String code);
YearService:
public class YearService {
#Autowired
private YearRepository yearRepository;
public List<Year> listAll() {
return yearRepository.findAll();
}
public void save(Year engineSize) {
yearRepository.save(engineSize);
}
public Year get(long id) {
return yearRepository.findById(id).get();
}
public void delete(Long id) {
yearRepository.deleteById(id);
}
public int getYearByCode(String code) {
//here, we're using this method just as you've used the methods above.
//Spring constructs the query at runtime
return yearRepository.findByCode(code); //<-- usage of the custom method
}
}
BService:
public interface BService {
CarBrand findVehicleBrand(String name);
}
BrandService:
#Service
#Transactional
public class BrandService implements BService{
#Autowired
private BrandRepository brandRepository;
public List<Brand> listAll(){
return brandRepository.findAll();
}
public void save(Brand brand){
brandRepository.save(brand);
}
public Brand get (long id){
return brandRepository.findById(id).get();
}
public void delete (Long id){
brandRepository.deleteById(id);
}
#Override
public CarBrand findVehicleBrand(String name) {
//var brand = (List<Brand>) brandRepository.findVehicleBrand(name);
var brand = brandRepository.findByBrand(name); //<-- using the custom method in brandRepository
return brand;
}
}
Your RepsonseDto:
class RepsonseDto {
private String yearMade;
private brandName;
//getters and setters
/*Use #JsonProperty("Year Made") and #JsonProperty("Brand Name") on your getters. Otherwise, you will get json reposnse as: "yearMade" and "brandName"*/
}
Controller:
There are better ways to write controllers and inject dependencies. Let's keep it simple for now.
#RequestController
class YourController {
//inject dependencies
#Autowired
YearService yearService;
#Autowired
BrandService brandService;
#RequestMapping("/{vincode}")
// the definition for ResponseEntity is above
public ResponseEntity<RepsonseDto> getAttr(#PathVariable(value="vincode") String vincode) {
// create a ReponseEntity object
RepsonseDto retEntity = new RepsonseDto();
// do a check for null and expected length of vincode
if(vincode != null && vincode.length() == 5) {
String yr = vincode.substring(0,1);
String brand = vincode.substring(2,4);
retEntity.setYearMade(yearService.getYearByCode(yr));
retEntity.setBrandName(brandService.findVehicleBrand(brand));
System.out.println(yr);
}
return new ResponseEntity<>(retEntity, HttpStatus.OK)
}
NOTE: I didn't use an IDE to write this. There may be compiler errors. Hope this gives you an idea of it all fits in.

Java Hibernate Spring - Service Interface with default implementation

I have a Java database application using hibernate, with different Classes that have the same attributes (here: “active”).
In an interface, there is a function that retrieves entries from a database based on such an attribute (active).
So far, I was doing this:
//interface
public interface ObjSvcIntf {
default <Entity> ArrayList<Entity> get(Boolean active);
}
//implementation 1
public class ObjCarSvc implements ObjSvcIntf {
#SuppressWarnings("unchecked")
#Override
public ArrayList< ObjCar > get(Boolean active) {
#SuppressWarnings("rawtypes")
Query query = DB.s.createQuery("from " + ObjCar.class.getSimpleName() + " where active = :active");
query.setParameter("active", active);
if (!query.list().isEmpty()) {
return (ArrayList< ObjCar >) query.list();
} else {
return null;
}
}
//implementation 1
public class ObjPersonSvc implements ObjSvcIntf {
#SuppressWarnings("unchecked")
#Override
public ArrayList< ObjPerson > get(Boolean active) {
#SuppressWarnings("rawtypes")
Query query = DB.s.createQuery("from " + ObjPerson.class.getSimpleName() + " where active = :active");
query.setParameter("active ", active);
if (!query.list().isEmpty()) {
return (ArrayList< ObjPerson >) query.list();
} else {
return null;
}
}
As You can see, there is a lot of redundant code in each implementing class, which I would like to avoid.
What I would like instead therefore, is to have a generic default function in the interface, which will return the same for each implementation of the interface (unless overridden by the implementing class of course).
I.e., something like this (except this does not work, of course):
public interface ObjSvcIntf {
default <Entity> ArrayList<Entity> get(Boolean active) {
#SuppressWarnings("rawtypes")
Query query = DB.s.createQuery("from " + Entity.class.getSimpleName() + " where active = :active");
query.setParameter("active", active);
return (ArrayList<Entity>) query.list();
}
}
I am lacking the proper understanding here, how to create the function in the interface in the right way, to be able to use it in different contexts/ different classes.
How can I adjust the function in the interface instead to make this happen?
public interface ObjSvcIntf<Entity> {
default <Entity> ArrayList<Entity> get(Boolean active) {
#SuppressWarnings("rawtypes")
Query query = DB.s.createQuery("from " + getImplClass().getSimpleName() + " where active = :active");
query.setParameter("active", active);
return (ArrayList<Entity>) query.list();
}
Class getImplClass();
}
And you could just provide that same class for each implementation as you provide for the generic type.
You can create an abstract function to return the object of the subclass. Something like this would work. Here is example code, where interface returns as list of object of the class implementing the interface.
public interface ObjSvcIntf<E> {
default List<E> get(Boolean active) {
var list = new ArrayList<E>();
list.add(self());
return list;
}
E self(); // function to return the sub class instance
}
I restructured the project to separate the Interface from its implementation.
Each class, extending the (abstract) implementation of the interface now sets an attribute of Type "Class" when calling the super constructor, with each function in the abstract class referring to that attribute.
Is there a better way?
What are potential problems with this approach?
Interface:
public interfaceObjSvcIntf {
<Entity> Object getById(Long id);
}
Implementing abstract Class:
public abstract class ObjSvcImpl implements ObjSvcIntf {
public Class<?> servicedClass;
// CONSTRUCTOR
public ObjSvcImpl(Class<?> servicedClass) {
this.servicedClass = servicedClass;
}
#Override
public <Entity> Object getById(Long id) {
return DB.getById(this.servicedClass, id);
}
}
Service Class:
public class ObjCarSvc extends ObjSvcImpl {
public ObjCarSvc() {
super(ObjCar.class);
}
}
Model Class:
#Entity
#Table(name = "OBJ_CAR")
public class ObjCar implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "OBJ_CAR_ID")
private Long objCarId;
#NotNull
#Column(name = "NAME")
private String name;
// Getters and Setters
}

Using reflection to get a specific attribute from a extended instance

I would like to make a generic method to get a List from the parameter object.
The problem is because I have a declared object with a instance of the other class that extends the declared class.
I don't want to use the instanceof solution because the number of classes that extends LimitedValue can be big.
I thought to use reflection for a solution, but I don't know how to use that with an instance of object, in this part of the code:
Class cls = Class.forName(limitedValue.getClass().getName());
Object obj = cls.newInstance();
//This is wrong, I don't want a new instance.
Method[] methods = cls.getDeclaredMethods();
for(int x= 0; x < methods.length; x++) {
Method method = methods[x];
if ("java.util.List".equals(method.getReturnType().getName())) {
//How to get the value of this method from limitedValue instance ?
}
}
This is my full code:
public class CalculatorLimitedValue {
public static void main(String[] args) throws Exception {
StoreItem storeItem = new StoreItem(1L, "Name of StoreItem", 50L);
List listOfStoreItems = new ArrayList();
listOfStoreItems.add(storeItem);
LimitedValue limitedValue0 = new Store(listOfStoreItems);
List firstList = calculator(limitedValue0);
//do something with the list
SupermarketItem supermarketItem = new SupermarketItem(1L, "Name of SupermarketItem", 21L);
List listOfSupermarketItems = new ArrayList();
listOfSupermarketItems.add(supermarketItem);
LimitedValue limitedValue1 = new Supermarket(listOfSupermarketItems);
List secondList = calculator(limitedValue1);
//do something with the list
}
/** This is the method that I'd like to make generic to return a List */
private static List calculator(LimitedValue limitedValue) throws Exception{
Class cls = Class.forName(limitedValue.getClass().getName());
Object obj = cls.newInstance();
//This is wrong, I don't want a new instance.
Method[] methods = cls.getDeclaredMethods();
for(int x= 0; x < methods.length; x++) {
Method method = methods[x];
if ("java.util.List".equals(method.getReturnType().getName())) {
//How to get the value of this method from limitedValue instance ?
}
}
/* I don't want to use this one way, because my classes that extends LimitedValue
can be big. I would like to made a generic way to get de list of classes. */
if (limitedValue instanceof Store) {
System.out.println("This is a store");
return ((Store) limitedValue).getStoreItems();
} else if (limitedValue instanceof Supermarket) {
System.out.println("This is a supermarket");
return ((Supermarket) limitedValue).getSupermarketItems();
}
return null;
}
}
If it help, these are my other classes:
LimitedValue.class
public class LimitedValue { }
StoreItem.class
public class StoreItem {
private Long id;
private String nameOfStoreItem;
private Long valueOfStoreItem;
public StoreItem(Long id, String nameOfStoreItem, Long valueOfStoreItem){
this.id = id;
this.nameOfStoreItem = nameOfStoreItem;
this.valueOfStoreItem = valueOfStoreItem;
}
//getters and setters...
}
SupermarketItem.class
public class SupermarketItem {
private Long id;
private String nameOfSupermarketItem;
private Long valueOfSupermarketItem;
public SupermarketItem() {
}
public SupermarketItem(Long id, String nameOfSupermarketItem, Long valueOfSupermarketItem) {
this.id = id;
this.nameOfSupermarketItem = nameOfSupermarketItem;
this.valueOfSupermarketItem = valueOfSupermarketItem;
}
//getters and setters...
}
Store.class
public class Store extends LimitedValue {
private List<StoreItem> storeItems;
public Store(List<StoreItem> storeItems) {
this.storeItems = storeItems;
}
//getters and setters
}
Supermarket.class
public class Supermarket extends LimitedValue {
private List<SupermarketItem> supermarketItems;
public Supermarket(List<SupermarketItem> supermarketItems) {
this.supermarketItems = supermarketItems;
}
//getters and setters
}
You could try to use reflection here to try to achieve what you want, but it would be better to reconsider your overall design and try to use a better object oriented design that solves the problem at hand.
In particular, lets say we consider adding a method called getItems to the LimitedValue class that returns a List of items, which may be SupermarketItems or may be StoreItems. If it is structured correctly, you won't need to know the actual type because the code will be abstracted over it polymorphically.
public abstract class LimitedValue {
List<? extends Item> getItems();
}
We've now defined a new method on LimitedValue, but we also have to consider that we've introduced this new Item thing. I note that the SupermarketItem and StoreItem all share similiar attributes, name, id and value, so it seems that it might be possible to use a single class to represent them all.
public abstract class Item {
final Long id;
final String name;
final Long value;
public Item(final Long id, final Long name, final Long value) {
this.id = id;
this.name = name;
this.value = value;
}
String getName() {
return name;
}
// other getters and setters
}
public class SupermarketItem extends Item {
public SupermarketItem(final Long id, final Long name, final Long value) {
super(id, name, value);
}
}
public class StoreItem extends Item {
public StoreItem(final Long id, final Long name, final Long value) {
super(id, name, value);
}
}
Now we've completely abstracted away the need for any reflection when accessing these objects - you can simply call item.getValue() as you will know that every item in the list is of type Item.
Of course, you'll also need to refactor the Store and SuperMarket classes, for example:
public class Supermarket extends LimitedValue {
private List<SupermarketItem> supermarketItems;
public Supermarket(List<SupermarketItem> supermarketItems) {
this.supermarketItems = supermarketItems;
}
public List<? extends Item> getItems() {
return supermarketItems;
}
}
and because you are only returning a List<Item> you always know what is in it, and you can change your main code to work with this.
This is a much cleaner long term solution.
To get the List value, use Method#invoke:
List list = method.invoke(limitedValue);
You don't need Object obj = cls.newInstance(); - you're not using it at all in the method.
In any case, you're making it very difficult for yourself. You could also define an interface
public interface HasList<E> {
List<E> getList();
}
and have all classes implement this.

Get Object from Field

CLARIFICATION:
I do not know the objects name. That is where the problem comes in. I am creating an object like such:
`new Object(String attributes);
I am trying to run code in another class such as:
***.getStuff();
the trick to it is, there is no name for the Object. but i do know what String attributes is
The question: Is there any way to accomplish this without using the dreaded for loop?
This question is a bit tricky to word, but I will try my best. What I want to is get an object that matches a particular field without making a messy for loop. Something along the lines of:
Object A has the field String name.
String nameObj = "Tickle";
Object A has the name "Tickle"
if(nameObj.equals(Object A)){
//bla bla
}
Very confusing wording, yes. Sorry about that. I want to use Object A in my code without having to figure out which object it is, assuming all I have is its name. I am looking for a shortcut around using a for loop, I suppose.
Feel free to ask questions about what I am looking for. Sorry about the terribly worded question.
Poor coding, but this is what I am looking for...
nameObj.getName().getObjectA();
If you have a bunch of objects with names, and you want to grab an object by its name, I suggest you look up the class HashMap. HashMap lets you put in objects under keys, and when you give the hash map a key it returns the object associated with that key. So in your example, the keys would be string names.
Take at this implementation, that demonstrates what #Patashu said, create a map to the objects, in this case I just add an abstract class at the top of all.
import java.util.HashMap;
public class FindMeBaby {
public static void main(String[] args) {
Factory.add(new NiceGuy("first one"));
Factory.add(new FirstChild("ok im late"));
System.out.println(Factory.get("first one")
.getVeryImportantInformationThatOnlyThisClassKnows());
}
}
abstract class ParentOfAll {
protected String id;
public ParentOfAll(String id) {
this.id = id;
}
public String getId(){
return id;
}
public abstract String getVeryImportantInformationThatOnlyThisClassKnows();
}
class FirstChild extends ParentOfAll {
public FirstChild(String id) {
super(id);
}
public String getVeryImportantInformationThatOnlyThisClassKnows() {
return "this is a secret";
}
}
class NiceGuy extends ParentOfAll {
public NiceGuy(String id) {
super(id);
}
public String getVeryImportantInformationThatOnlyThisClassKnows() {
return "to say the true, i'm not that nice :)";
}
}
class Factory {
private static HashMap allTheObjects = new HashMap();
public static Object add(ParentOfAll object) {
allTheObjects.put(object.getId(), object);
return object;
}
public static ParentOfAll get(String key) {
return (ParentOfAll) allTheObjects.get(key);
}
}
This is another version, of the same implementation with a more transparent aproach, without the Factory class, the Parent itself will keep track of the instances and save in a list.
import java.util.HashMap;
public class FindMeBaby {
public static void main(String[] args) {
NiceGuy foo = new NiceGuy("first one");
FirstChild bar = new FirstChild("ok im late");
System.out.println(ParentOfAll.get("first one")
.getVeryImportantInformationThatOnlyThisClassKnows());
}
}
abstract class ParentOfAll {
protected String id;
public ParentOfAll(String id) {
this.id = id;
add(this);
}
public String getId() {
return id;
}
public abstract String getVeryImportantInformationThatOnlyThisClassKnows();
private static HashMap allTheObjects = new HashMap();
private static Object add(ParentOfAll object) {
allTheObjects.put(object.getId(), object);
return object;
}
public static ParentOfAll get(String key) {
return (ParentOfAll) allTheObjects.get(key);
}
}
class FirstChild extends ParentOfAll {
public FirstChild(String id) {
super(id);
}
public String getVeryImportantInformationThatOnlyThisClassKnows() {
return "this is a secret";
}
}
class NiceGuy extends ParentOfAll {
public NiceGuy(String id) {
super(id);
}
public String getVeryImportantInformationThatOnlyThisClassKnows() {
return "to say the true, i'm not that nice :)";
}
}

Categories

Resources