Room is not finding setType method defined in the parent class. Gives cannot find setter for field error during compilation.
Parent class
public class Data {
private int type = -1;
public Data() {
}
public int getType() {
return type;
}
public Data setType(int type) {
this.type = type;
return this;
}
}
Child class
#Entity
public class Log extends Data {
#PrimaryKey(autoGenerate = true)
public int id;
public Log() {
}
}
Usually setters do not return values.
Change your setType() method to:
public void setType(int type) {
this.type = type;
}
P.S. Obviously, returning the same instance of Data object is useless here, since you're invoking the method on that object and already have it.
If you want to keep the builder pattern, you could consider using an internal static class for that matter as follows (you don't need an empty constructor, that's added implicitly):
public class Data {
private int type = -1;
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public static class Builder {
private Data data = new Data();
public Builder setType(int type) {
data.setType(type);
return this;
}
public Data build() {
return data;
}
}
}
Now, for creating a data class you could do:
Data data = new Data.Builder()
.setType(10)
.build();
Related
Using Jackson, I want to deserialize some values into generic wrapper objects for which I have a specific static factory method for each type.
However, Jackson does not seem to pick up on this layer of indirection, even if I annotate the factory methods with #JsonCreator.
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of Wrapped (no Creators, like default constructor, exist): no String-argument constructor/factory method to deserialize from String value ('Carl')
How can I make Jackson use the factory methods that return wrappers with a generic type?
This self-contained code illustrates my problem:
class Request {
// I want to deserialize into these fields
#JsonProperty Wrapped<Person> person;
#JsonProperty Wrapped<Score> score;
}
class Wrapped<T> {
// This is my generic wrapper type.
// Its construction is non-trivial: it is impossible to first construct the value before wrapping it.
// Therefor, construction is performed by the factory methods of the concrete value classes (Person, Score, ...).
// Let's say for simplicity that it did have a simple constructor:
T value;
public Wrapped(T value) {
this.value = value;
}
}
class Person {
#JsonCreator
public static Wrapped<Person> createWrapped(String name) {
// complex construction of the wrapped person
return new Wrapped<>(new Person(name));
}
#JsonValue
String name;
public Person(String name) {
this.name = name;
}
}
class Score {
#JsonCreator
public static Wrapped<Score> createWrapped(int score) {
// complex construction of the wrapped score
return new Wrapped<>(new Score(score));
}
#JsonValue
int score;
public Score(int score) {
this.score = score;
}
}
class Example {
private static final String JSON_REQUEST =
"""
{
"person":"Carl",
"score":20
}
""";
public static void main(String[] args) throws Exception {
Request request = new ObjectMapper()
.readValue(JSON_REQUEST, Request.class);
System.out.println(request.person.value.name);
System.out.println(request.score.value.score);
}
}
It is important to note that type information is only in the java classes, it should not be in the json.
One solution, add a DTO:
public class RequestDTO {
#JsonValue
String person;
#JsonValue
Integer score;
/**
* #return the person
*/
public String getPerson() {
return person;
}
/**
* #return the score
*/
public Integer getScore() {
return score;
}
/**
* #param person the person to set
*/
public void setPerson(String person) {
this.person = person;
}
/**
* #param score the score to set
*/
public void setScore(Integer score) {
this.score = score;
}
public RequestDTO() {
}
public RequestDTO(String person, Integer score) {
this.person = person;
this.score = score;
}
}
And change Request definition to use Mode.DELEGATING
public class Request {
// I want to deserialize into these fields
#JsonProperty Wrapped<Person> person;
#JsonProperty Wrapped<Score> score;
#JsonCreator(mode=Mode.DELEGATING)
public static Request createWrapped(RequestDTO requestDTO) {
// complex construction of the wrapped person
Request req = new Request();
req.person = new Wrapped<>(new Person(requestDTO.getPerson()));
req.score = new Wrapped<>(new Score(requestDTO.getScore()));
return req ;
}
}
#p3consulting's answer sent me in the right direction, but it lead to something completely different.
Jackson has something called a Converter that does exactly what I want.
I created converters for each wrapped value type,
and then annotated the properties in the request to use those converters:
class Request {
#JsonDeserialize(converter = WrappedPersonConverter.class)
Wrapped<Person> person;
#JsonDeserialize(converter = WrappedScoreConverter.class)
Wrapped<Score> score;
}
class WrappedPersonConverter
extends StdConverter<String, Wrapped<Person>> {
#Override
public Wrapped<Person> convert(String value) {
return Person.createWrapped(value);
}
}
class WrappedScoreConverter
extends StdConverter<Integer, Wrapped<Score>> {
#Override
public Wrapped<Score> convert(Integer score) {
return Score.createWrapped(score);
}
}
For factory methods with more complex signatures, you can make this work by using a DTO, e.g.:
class WrappedPersonConverter2
extends StdConverter<WrappedPersonConverter2.DTO, Wrapped<Person>> {
#Override
public Wrapped<Person> convert(WrappedPersonConverter2.DTO dto) {
return Person.createWrapped(dto.first, dto.last);
}
public static class DTO {
public int first;
public int last;
}
}
I cannot believe this was so simple but took me so long to find.
I have a base class (Foo) with 2 children (A and B). They look like this:
public abstract class Foo {
private String fooString;
public Foo(String fooString) {
this.fooString = fooString;
}
//getter
}
#JsonDeserialize(builder = A.ABuilder.class)
public class A extends Foo {
private int amount;
public A(String fooString, int amount) {
super(fooString);
this.amount = amount;
}
//getter
#JsonPOJOBuilder
public static class ABuilder {
private String fooString;
private int amount;
public ABuilder withFooString(final String fooString) {
this.fooString = fooString;
return this;
}
public ABuilder withAmount(final int amount) {
this.amount = amount;
return this;
}
public A build() {
return new A(fooString, amount);
}
}
}
#JsonDeserialize(builder = B.BBuilder.class)
public class B extends Foo {
private String type;
public B(String fooString, String type) {
super(fooString);
this.type = type;
}
//getter
#JsonPOJOBuilder
public static class BBuilder {
private String fooString;
private String type;
public BBuilder withFooString(final String fooString) {
this.fooString = fooString;
return this;
}
public BBuilder withType(final String type) {
this.type = type;
return this;
}
public B build() {
return new B(fooString, type);
}
}
}
In my controller I have this endpoint:
#PutMapping
private ResponseEntity<Foo> doSomething(#RequestBody Foo dto) {
//stuff
}
But whenever I try to send over my json payload:
{
"fooString":"test",
"amount":1
}
I get the error:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.test.Foo` (no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
at [Source: (String)"{"fooString":"test","amount":1}; line: 1, column: 1]
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1451)
at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1027)
at com.fasterxml.jackson.databind.deser.AbstractDeserializer.deserialize(AbstractDeserializer.java:265)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4013)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3004)
at AbstractJackson.main(AbstractJackson.java:11)
How do I get jackson to deserialize the json into the proper child class? What am I doing wrong?
The base class won't get the constructors of the sub classes instead it is quite the opposite,you cannot set subclass specific properties in base class instead you need to use specific subclass for the call or use custom deserializer for base class with correct use intanceOf
The easiest way to get it working is to change the controller method.
#PutMapping
private ResponseEntity<Foo> doSomething(#RequestBody A dto) {
//stuff
}
I am trying to generify following class:
public class FooService {
private Client client;
public Foo get(Long id) {
return client.get(id, Foo.class);
}
public List<Foo> query() {
return Arrays.asList(client.get(Foo[].class));
}
}
Everything is alright except Foo[].class:
public abstract class BaseService<T, I> {
private Client client;
private Class<T> type;
public BaseService(Class<T> type) {
this.type = type;
}
public T get(I id) {
return client.get(id, type);
}
public List<T> query() {
return Arrays.asList(client.get(/* What to pass here? */));
}
How can I solve this issue without passing Foo[].class in the constructor like I have done with Foo.class?
Java lacks facilities to obtain an array class from element class directly. A common work-around is to obtain the class from a zero-length array:
private Class<T> type;
private Class arrType;
public BaseService(Class<T> type) {
this.type = type;
arrType = Array.newInstance(type, 0).getClass();
}
You can now pass arrType to the client.get(...) method.
Why don't you do something like this:
public class Client<T> {
T instance;
T get(long id) {
return instance;
}
List<T> get(){
return new ArrayList<>();
}
}
class FooService<T> {
private Client<T> client;
public T get(Long id) {
return client.get(id);
}
public List<T> query() {
return client.get();
}
}
I'd like to know whether my implementation of QuestionBuilder violates mutability.
public class Question<T extends Serializable> implements Serializable {
private QuestionHolder<T> questionHolder;
private Question(QuestionHolder<T> questionHolder) {
this.questionHolder = questionHolder;
}
public String getId() {
return questionHolder.id;
}
public int getOrder() {
return questionHolder.order;
}
public QuestionType getType() {
return questionHolder.type;
}
public boolean isImmediate() {
return questionHolder.immediate;
}
public boolean isMandatory() {
return questionHolder.mandatory;
}
public List<T> getSelectedValues() {
return questionHolder.selectedValues;
}
public List<T> getPossibleValues() {
return questionHolder.possibleValues;
}
private static final class QuestionHolder<T extends Serializable> {
private String id;
private int order = 0;
private QuestionType type;
private boolean immediate;
private boolean mandatory;
private List<T> selectedValues;
private List<T> possibleValues;
}
public static final class QuestionBuilder<T extends Serializable> implements Builder<Question<T>> {
private QuestionHolder<T> questionHolder;
public QuestionBuilder(String id) {
questionHolder = new QuestionHolder<>();
questionHolder.id = id;
}
public QuestionBuilder withOrder(int order) {
questionHolder.order = order;
return this;
}
public QuestionBuilder withType(QuestionType questionType) {
questionHolder.type = questionType;
return this;
}
public QuestionBuilder withImmediate(boolean immediate) {
questionHolder.immediate = immediate;
return this;
}
public QuestionBuilder withMandatory(boolean mandatory) {
questionHolder.mandatory = mandatory;
return this;
}
public QuestionBuilder withSelectedValues(List<T> selectedValues) {
questionHolder.selectedValues = selectedValues;
return this;
}
public QuestionBuilder withPossibleValues(List<T> possibleValues) {
questionHolder.possibleValues = possibleValues;
return this;
}
public Question<T> build() {
Question<T> question = new Question<>(questionHolder);
questionHolder = null;
return question;
}
}
}
Or what should I adjust in order to resolve mutability issue. Any suggestions?
If you're worried about thread safety, then your code here is not necessarily thread safe.
It is possible that one thread calls build() and returns a Question pointing to a QuestionHolder. Even though build() sets the holder to null, another thread might not see that null, but instead see the old value of the field. If that other thread called any of your setters, it would potentially mutate the Holder that the Question class had already accessed.
In a single threaded application you would be fine.
As far as I can see, you are mutating the QuestionHolder with each builder call.
What I would do is:
1) Make all properties inside QuestionHolder private and don't create any setters at all.
2) Store each property inside the builder instance and create a new instance of QuestionHolder in the build method of the builder.
For example:
public Question<T> build() {
// DO ALL THE VALIDATIONS NEEDED
QuestionHolder holder = new QuestionHolder(id, order, type, inmediate, mandatory, selectedValues, possibleValues);
return new Question<>(questionHolder);
}
With these approach, you will be mutating the Builder, but that's ok for the Builder Pattern. You will obviously need to create a new Builder instance each time you want to create a Question. If you want to use the same Builder over and over again you will probably need to store some kind of structure inside it (a Map identified by Id, for example).
My controller is annotated as
public ModelAndView execute(final HttpServletRequest request, #ModelAttribute final UploadFormBean uploadFormBean) {
//some code.
Type t = uploadFormBean.getType(); //t is null.
//some more code.
}
The UploadFormBean is defined as:
public class UploadFormBean {
private Type type;
public enum Type {
A ("abc"),
B ("xyz"),
C ("pqr");
private final String str;
private Type(final String str) {
this.str = str;
}
#Override
public String toString() {
return str;
}
}
public Type getType() {
return type;
}
public void setType(final String type) {
for (Type s: Type.values()) {
if (s.toString().equalsIgnoreCase(type)) {
this.type = s;
}
}
}
}
Why is #mMdelAttribute not able to set type variable (t is null in execute function)?
What am I missing? Also, please explain how does #ModelAttribute binds the data members from http request to a java bean.
Note: this works fine in case when type is a String and setType is defined as:
void setType(final String type) {
this.type = type;
}
JSP:
<input type="hidden" name="type" value="abc">
<input type="hidden" name="type" value="xyz">
1)Why is #mMdelAttribute not able to set type variable (t is null in execute function)?
Because for binding it will expect a setter like like one below.
public void setType(final Type type) {
this.type = type) ;
}
But this wont work as path value in spring form,because enum will not have
public constructor.
So better way to achieve this is to re factor your bean like one below
public class UploadFormBean {
private String type;
public enum Type {
A ("abc"),
B ("xyz"),
C ("pqr");
private final String str;
private Type(final String str) {
this.str = str;
}
#Override
public String toString() {
return str;
}
}
public String getType() {
return type;
}
public void setType(String type) {
for (Type s: Type.values()) {
if (s.toString().equalsIgnoreCase(type)) {
this.type = s.name();
}
}
}
}