Unsatisfied dependency expressed through constructor parameter - java

Error Message I am getting
Error creating bean with name 'libraryController' defined in file :
Unsatisfied dependency expressed through constructor parameter 0:
Error creating bean with name 'libraryService' defined in file.
Unsatisfied dependency expressed through constructor parameter 2:
Error creating bean with name 'lendRepository' defined in
com.restapi.respository.LendRepository defined in
#EnableDynamoDBRepositories declared on DynamoDBConfig: Could not
create query for public abstract java.util.Optional
com.restapi.respository.LendRepository.findByBookAndStatus(com.restapi.model.Book,com.restapi.model.LendStatus);
Reason: No property 'book' found for type 'Lend' Did you mean
''bookId''
LendRepository.Java:
import org.socialsignin.spring.data.dynamodb.repository.EnableScan;
import com.restapi.model.Book;
import com.restapi.model.Lend;
import com.restapi.model.LendStatus;
import org.springframework.data.repository.CrudRepository;
import java.util.Optional;
#EnableScan
public interface LendRepository extends CrudRepository<Lend, String> {
Optional<Lend> findByBookAndStatus(Book book, LendStatus status);
}
Book.java:
package com.restapi.model;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAutoGeneratedKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;
import lombok.Getter;
import lombok.Setter;
#Getter
#Setter
#DynamoDBTable(tableName = "book")
public class Book {
#DynamoDBHashKey
#DynamoDBAutoGeneratedKey
private String id;
#DynamoDBAttribute
private String name;
#DynamoDBAttribute
private String isbn;
#DynamoDBAttribute
private String authorId;
}
LibraryService.java:
public List<String> lendABook (BookLendRequest request) throws Exception {
Optional<Member> memberForId = memberRepository.findById(request.getMemberId());
if (!memberForId.isPresent()) {
throw new Exception("Exception message");
}
Member member = memberForId.get();
if (member.getStatus() != MemberStatus.ACTIVE) {
throw new RuntimeException("User is not active to proceed a lending.");
}
List<String> booksApprovedToBurrow = new ArrayList<>();
request.getBookIds().forEach(bookId -> {
Optional<Book> bookForId = bookRepository.findById(bookId);
if (!bookForId.isPresent()) {
try {
throw new Exception("Exception message");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Optional<Lend> burrowedBook = lendRepository.findByBookAndStatus(bookForId.get(), LendStatus.BURROWED);
if (!burrowedBook.isPresent()) {
booksApprovedToBurrow.add(bookForId.get().getName());
Lend lend = new Lend();
lend.setMemberId(memberForId.get().getId());
lend.setBookId(bookForId.get().getId());
lend.setStatus(LendStatus.BURROWED);
lend.setStartOn(Instant.now().toString());
lend.setDueOn(Instant.now().plus(30, ChronoUnit.DAYS).toString());
lendRepository.save(lend);
}
});

The error message and solution suggestion is pretty obvious.
Could not create query for public abstract java.util.Optional com.restapi.respository.LendRepository.findByBookAndStatus(com.restapi.model.Book,com.restapi.model.LendStatus); Reason: No property 'book' found for type 'Lend' Did you mean ''bookId''
Your findByBookAndStatus() method that you created in LendRepository appears incorrect. You don't have a book property for your Lend object. Perhaps you are keeping the id value of the Book as a property in your Lend object.
If you have an attribute named bookId in your Lend object, your method should be:
Optional<Lend> findByBookIdAndStatus(ID id, LendStatus status);
Your first argument in the method should be the same as the data type of the id attribute of your Book object.

Annotate 'LibraryService' class with #Service.

Related

The method getType() is undefined for the type Ingredient

package tacos.web;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes;
import java.lang.reflect.Field;
import lombok.extern.slf4j.Slf4j;
import tacos.Ingredient;
import tacos.Ingredient.Type;
import tacos.Taco;
#Slf4j
#Controller
#RequestMapping("/design")
#SessionAttributes("tacoOrder")
public class DesignTacoController {
#ModelAttribute
public void addIngredientsToModel(Model model) {
List<Ingredient> ingredients = Arrays.asList(
new Ingredient("FLTO", "Flour Tortilla", Type.WRAP),
new Ingredient("COTO", "Corn Tortilla", Type.WRAP),
new Ingredient("GRBF", "Ground Beef", Type.PROTEIN),
new Ingredient("CARN", "Carnitas", Type.PROTEIN),
new Ingredient("TMTO", "Diced Tomatoes", Type.VEGGIES),
new Ingredient("LETC", "Lettuce", Type.VEGGIES),
new Ingredient("CHED", "Cheddar", Type.CHEESE),
new Ingredient("JACK", "Monterrey Jack", Type.CHEESE),
new Ingredient("SLSA", "Salsa", Type.SAUCE),
new Ingredient("SRCR", "Sour Cream", Type.SAUCE)
);
Type[] types = Ingredient.Type.values();
for (Type type : types) {
model.addAttribute(type.toString().toLowerCase(),
filterByType(ingredients, type));
}
}
#GetMapping
public String showDesignForm(Model model) {
model.addAttribute("taco", new Taco());
return "design";
}
private Iterable<Ingredient> filterByType(
List<Ingredient> ingredients, Type type) {
return ingredients
.stream()
.filter(x -> x.getType().equals(type))
.collect(Collectors.toList());
}
}
I was going through the book Spring in action edition 6 chapter. In that in the filterByType method the '.getType()' is showing the error
The method getType() is undefined for the type Ingredient
I thought it was the error due to lombok but I have installed that as well. I have also import the package 'java.lang.reflect.Field' but still getting the error.
package tacos;
import lombok.Data;
#Data
public class Ingredient {
public Ingredient(String string, String string2, Type wrap) {
// TODO Auto-generated constructor stub
}
private final String id = "";
private final String name = "";
private final Type type = null;
public enum Type {
WRAP, PROTEIN, VEGGIES, CHEESE, SAUCE
}
}
The above class is the Ingredient Class
Seems you are not the first person who faced with this issue https://coderanch.com/t/730026/java/lombok
In addIngredientsToModel of class DesignTacoController the flagged
error is "The constructor Ingredient(String, String, Ingredient.Type)
is undefined". Also, in method filterByType the flagged error is "The
method getType() is undefined for the type Ingredient". It zappears
that lombok is just not working. But I have lombok in the pom:
Answer:
Just adding Lombok as a dependency does not make Eclipse recognize it,
you'll need a plugin for that. See https://www.baeldung.com/lombok-ide
for instructions on installing Lombok into Eclipse (and IntelliJ for
those who prefer it).

Jackson ignore subtype property when deserialize

I'm using a subType property in Jackson, and I want to using this property when deserializing json.
package com.gaosoft.ai.kg.commons.sphinx.strategy;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.sankuai.ai.kg.commons.sphinx.model.FAQRecord;
import com.sankuai.ai.kg.commons.sphinx.model.FAQRequest;
import org.springframework.beans.factory.BeanFactory;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
property = "strategyType"
)
#JsonSubTypes({
#JsonSubTypes.Type(value = StrategyEmpty.class, name = "empty"),
#JsonSubTypes.Type(value = StrategyNormal.class, name = "normal"),
#JsonSubTypes.Type(value = StrategyDummy.class, name = "dummy")
}
)
public abstract class Strategy implements Serializable {
private String strategyName;
private String strategyType;
private Map<String, Object> args = new HashMap<>();
public String getStrategyType() {
return strategyType;
}
public void setStrategyType(String strategyType) {
this.strategyType = strategyType;
}
public Map<String, Object> getArgs() {
return args;
}
public void setArgs(Map<String, Object> args) {
this.args = args;
}
public String getStrategyName() {
return strategyName;
}
public void setStrategyName(String strategyName) {
this.strategyName = strategyName;
}
public abstract void init(BeanFactory beanFactory);
public abstract List<FAQRecord> fetchFAQ(FAQRequest request);
}
Like my code says, there are 3 subtype of abstract class Strategy, and I want to retain the subclass type name in strategyType property.
Is there a way to fill strategyType when using jackson in this way?
(Sorry about my poor English)
I think what you're asking for is the #JsonTypeInfo#visible property:
Note on visibility of type identifier: by default, deserialization (use during reading of JSON) of type identifier is completely handled by Jackson, and is not passed to deserializers. However, if so desired, it is possible to define property visible = true in which case property will be passed as-is to deserializers (and set via setter or field) on deserialization.
So in your example,
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
property = "strategyType",
visible = true
)
That said, this seems like a design smell. Is it truly valid that you can set a StrategyEmpty's strategyType to dummy? If not, and StrategyEmpty should always have a strategyType of empty, then why not just have an abstract getStrategyType() that each subclass implements with a hardcoded value?

How to turn off deserialization for enum

I would like to turn off deserialization for concrete enum. Is it possible?
Exercise model class:
package main.exercise;
import lombok.*;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
#AllArgsConstructor
#NoArgsConstructor
#Getter
#Entity
#Builder
public class Exercise {
#Id
#GeneratedValue
private int id;
#NonNull
private String name;
#NonNull
private ExerciseType exerciseType;
private double caloriesBurned;
private String exerciseDescription;
}
I got method in controller:
#PostMapping("/addExercise")
public List<String> addExercise(#RequestBody Exercise exercise) {
return exerciseCrudActivitiesService.addExercise(exercise);
}
which takes Exercise body and if type of Exercise is wrong I got error while POST http request:
Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `main.exercise.ExerciseType` from String "CARdDIO": not one of the values accepted for Enum class: [CARDIO, WEIGHTLIFTING]; nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `main.exercise.ExerciseType` from String "CARdDIO": not one of the values accepted for Enum class: [CARDIO, WEIGHTLIFTING]
at [Source: (PushbackInputStream); line: 4, column: 25] (through reference chain: main.exercise.Exercise["exerciseType"])]
The point is in service I got validator, which validates whether type of enum is right or wrong and return string to list of errors from all validators. Unfortunately this code cannot be reached because of error.
public List<String> addExercise(Exercise exercise) {
ExerciseValidator validator = new ExerciseValidator();
List<String> messages = validator.validate(exercise);
if (messages.isEmpty()) {
exerciseRepository.save(exercise);
}
return messages;
}
Validator
package main.exercise.validator.attributesvalidators;
import main.exercise.Exercise;
import main.exercise.ExerciseType;
import main.exercise.validator.ExerciseAttributesValidator;
import java.util.InputMismatchException;
public class ExerciseTypeValidator implements ExerciseAttributesValidator {
#Override
public String validate(Exercise exercise) {
if (exercise.getExerciseType() == null) {
return "You didn't put exercise type!";
}
try {
ExerciseType.forName(exercise.getExerciseType().name());
} catch (InputMismatchException e) {
return "Wrong exercise type!";
}
return null;
}
}
To turn off (de-)serialization, you can add the #JsonIgnore to the exerciseType field. However, I don't think this will help you anyways.
If serialization is ignored, the field would always be null which is not the intended behavior.
Your validator is too late. Note: the validate method takes an Exercise object as a parameter. The problem occurs during the creation of this object already.
When you get to the point that the line ExerciseType.forName(exercise.getExerciseType().name()); get's executed, it will NEVER throw an exception, because getExerciseType() is already a valid enum.
Instead of this custom validator, you could make use of a Spring #ControllerAdvice to register your own Exception handler for that error type.
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import com.fasterxml.jackson.databind.exc.InvalidFormatException
#ControllerAdvice
public class GlobalExceptionHandler {
#ExceptionHandler(InvalidFormatException.class)
public ResponseEntity<?> badFormatException(InvalidFormatException ex, WebRequest request) {
ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
}
}
See e.g. https://www.springboottutorial.com/spring-boot-exception-handling-for-rest-services for more details.

How to JAXB-marshall JavaFX Property classes when class is XmlAccessType.NONE?

I would like a Java class containing JavaFX Property objects (DoubleProperty, StringProperty, IntegerProperty) to be written into an XML file using JAXB's marshall() method call. However, this class contains lots of data that I do not want written into the XML. This class is expected to be modified by developers often, so I prefer to mark the class "#XmlAccessorType(XmlAccessType.NONE)" and then add #XmlElement tags to anything I want written into the XML (so a developer doesn't add some new member variables into this class and then accidentally alter the XML file's format).
I see examples such as http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-xsitype.html, but none of them have "#XmlAccessorType(XmlAccessType.NONE) " for their main class. When I add this tag to my class, I get either runtime Exceptions (because JAXB cannot create a new object) or an empty XML tag in the output (because JAXB created a default object of ome kind but didn't put the desired value into it). I have experimentes with dozens of #Xml* tag combinations but I cannot find one that works.
Note that I cannot annotate any of the DoubleProperty/SimpleDoubleProperty classes because they are part of the standard Java API.
Here is a code example, demonstrating the troubles with getting the bankAccountBalance property into the XML file. (you can ignore the other data - I started with Blaise Doughan's code as a starting-point for this example).
package Demo2;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlRootElement;
public class Demo2 {
public static void main(String[] args) throws Exception {
Customer customer = new Customer();
Address address = new Address();
address.setStreet("1 A Street");
customer.setContactInfo(address);
customer.setBankAccountBalance(123.45);
JAXBContext jc = JAXBContext.newInstance(Customer.class, Address.class, PhoneNumber.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(customer, System.out);
}
}
abstract class ContactInfo {
}
class Address extends ContactInfo {
private String street;
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
}
class PhoneNumber extends ContactInfo {
}
#XmlRootElement
#XmlAccessorType(XmlAccessType.NONE)
class Customer {
#XmlElement
private ContactInfo contactInfo;
// This tag runs OK but always outputs an empty XML tag ("<bankAccountBalance/>") regardless of the real value.
// #XmlElement
// This tag causes the following error:
// Exception in thread "main" com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
// Invalid #XmlElementRef : Type "class javafx.beans.property.DoubleProperty" or any of its subclasses are not known to this context.
// #XmlElementRef
// This tag causes the following error:
// Exception in thread "main" com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
// Invalid #XmlElementRef : Type "class javafx.beans.property.SimpleDoubleProperty" or any of its subclasses are not known to this context.
// #XmlElementRef(type=SimpleDoubleProperty.class)
private DoubleProperty bankAccountBalance;
public Customer() {
bankAccountBalance = new SimpleDoubleProperty(0);
}
public ContactInfo getContactInfo() {
return contactInfo;
}
public void setContactInfo(ContactInfo contactInfo) {
this.contactInfo = contactInfo;
}
public double getBankAccountBalance() {
return bankAccountBalance.get();
}
public void setBankAccountBalance(double bankAccountBalance) {
this.bankAccountBalance.set(bankAccountBalance);
}
}
Simply annotate the getter and not the DoubleProperty field, which nicely bypasses the javafx class. Don't forget to setValue so you see the result.
#XmlElement
public double getBankAccountBalance() {
return bankAccountBalance.get();
}

how do I register a custom conversion Service in spring 3 / webflow 2?

I've been trying to follow this example and using the reference to guide me, but I'm having no luck.
I've defined a converter:
import org.springframework.binding.convert.converters.StringToObject;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.text.ParseException;
import java.util.Date;
public class StringToDateTwoWayConverter extends StringToObject {
private DateFormat format = null;
public StringToDateTwoWayConverter () {
super(StringToDateTwoWayConverter.class);
format = new SimpleDateFormat("MM/dd/yyyy");
}
#Override
protected Object toObject(String string, Class targetClass) throws Exception {
Date date = null;
try {
date = format.parse(string);
} catch (ParseException e) {
e.printStackTrace();
return null;
}
return date;
}
#Override
protected String toString(Object object) throws Exception {
Date date = (Date) object;
return format.format(date);
}
}
and a conversionService:
import org.springframework.binding.convert.service.DefaultConversionService;
import org.springframework.stereotype.Component;
#Component("conversionService")
public class ApplicationConversionService extends DefaultConversionService
{
#Override
protected void addDefaultConverters() {
super.addDefaultConverters();
this.addConverter(new StringToDateTwoWayConverter());
this.addConverter("shortDate", new StringToDateTwoWayConverter());
}
}
and configured it:
<mvc:annotation-driven conversion-service="conversionService" />
<webflow:flow-builder-services id="flowBuilderServices" conversion-service="conversionService" .../>
(explicit instantiation shows the same error)
However, upon startup, I'm greeted with this exception:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name '(inner bean)': Unsatisfied dependency expressed through constructor argument with index 0 of type [org.springframework.core.convert.ConversionService]: Could not convert constructor argument value of type [com.yadayada.converter.ApplicationConversionService] to required type [org.springframework.core.convert.ConversionService]: Failed to convert value of type 'com.yadayada.converter.ApplicationConversionService' to required type 'org.springframework.core.convert.ConversionService'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [com.yadayada.converter.ApplicationConversionService] to required type [org.springframework.core.convert.ConversionService]: no matching editors or conversion strategy found
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:687)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:195)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:993)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:897)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:485)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:270)
... 60 more
I'm thoroughly puzzled why its not working. The conversion service implements ConversionService through its base class, so I don't see the problem. Any insight much appreciated!
In response to an answer below, I tried changing the service to implement the other Conversion service:
import org.springframework.stereotype.Component;
import org.springframework.core.convert.ConversionService;
import org.springframework.format.support.FormattingConversionService;
#Component ("conversionService")
public class ApplicationConversionService extends FormattingConversionService implements org.springframework.core.convert.ConversionService
{
public ApplicationConversionService() {
this.addConverter(new StringToDateConverter2());
}
}
But now I fail the other way:
Caused by: java.lang.IllegalStateException: Cannot convert value of type [com.yadayada.converter.ApplicationConversionService] to required type [org.springframework.binding.convert.ConversionService] for property 'conversionService': no matching editors or conversion strategy found
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:291)
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:155)
at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:461)
... 86 more
Spring MVC and Spring Webflow uses different hierarchies of type converters. So,
<mvc:annotation-driven ...> requires org.springframework.core.convert.ConversionService, but <webflow:flow-builder-services ...> requires org.springframework.binding.convert.ConversionService.
In above code you should write super(Date.class) instead super(StringToDateTwoWayConverter.class).

Categories