java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Enum - jax-rs

I get this error while trying to persist an entity 'UserAccount' into the database table.
#Entity
#Table(name = "user_account")
public class UserAccount extends BaseEntity {
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "useraccount_id")
#MapKeyEnumerated(EnumType.STRING)
private Map<PhoneType, PhoneNumber> phones = new HashMap<PhoneType, PhoneNumber>();
//... other attributes
//... default constructor, getters and setters
}
public enum PhoneType {
HOME("home"),
MOBILE("mobile"),
FAX("fax"),
WORK("work");
private String value;
PhoneType(String value) {
this.value = value;
}
#JsonValue
public String getValue() {
return value;
}
}
#Entity
#Table(name = "phone_number")
public class PhoneNumber extends BaseEntity {
private String areaCode;
private String number;
//... default constructor, getters and setters
}
and finally..
public class UserAccountRepository {
#Inject
EntityManager entityManager;
#Override
public UserAccount save(UserAccount userAccount) {
if (userAccount.getId() == null) {
entityManager.persist(userAccount);
} else {
userAccount = entityManager.merge(userAccount);
}
return userAccount;
}
//.. other methods
}
Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Enum
at org.eclipse.persistence.mappings.converters.EnumTypeConverter.convertObjectValueToDataValue(EnumTypeConverter.java:165)
at org.eclipse.persistence.mappings.foundation.AbstractDirectMapping.extractIdentityFieldsForQuery(AbstractDirectMapping.java:568)
at org.eclipse.persistence.internal.queries.MappedKeyMapContainerPolicy.getKeyMappingDataForWriteQuery(MappedKeyMapContainerPolicy.java:145)
at org.eclipse.persistence.mappings.OneToManyMapping.updateTargetRowPostInsertSource(OneToManyMapping.java:1425)
at org.eclipse.persistence.mappings.OneToManyMapping.performDataModificationEvent(OneToManyMapping.java:936)
at org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsWithChangeSet(CommitManager.java:162)
at org.eclipse.persistence.internal.sessions.AbstractSession.writeAllObjectsWithChangeSet(AbstractSession.java:4387)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabase(UnitOfWorkImpl.java:1493)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1583)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.issueSQLbeforeCompletion(UnitOfWorkImpl.java:3258)
at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.issueSQLbeforeCompletion(RepeatableWriteUnitOfWork.java:357)
at org.eclipse.persistence.transaction.AbstractSynchronizationListener.beforeCompletion(AbstractSynchronizationListener.java:160)
at org.eclipse.persistence.transaction.JTASynchronizationListener.beforeCompletion(JTASynchronizationListener.java:70)
at com.sun.enterprise.transaction.JavaEETransactionImpl.commit(JavaEETransactionImpl.java:452)
... 94 more
Other questions with same error suggest to add #Enumerated(EnumType.STRING) on the attribute of type Enum, I have used #MapKeyEnumerated(EnumType.STRING) on the phones Map, but I still see get this error. Any clues where am I wrong?
Please let me know if I haven't asked the question as per the SO guidance, I will correct it (as this is my 1st question).

I made a change to the PhoneNumber class as below
#Entity
#Table(name = "phone_number")
public class PhoneNumber extends BaseEntity {
private PhoneType type;
private String areaCode;
private String number;
//... default constructor, getters and setters
}
and then added #MapKey(name = "type") in the UserAccount as below.
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "useraccount_id")
#MapKeyEnumerated(EnumType.STRING)
#MapKey(name = "type")
private Map<PhoneType, PhoneNumber> phones = new HashMap<PhoneType, PhoneNumber>();
With these changes I am now able to save the UserAccount object successfully into the db tables.

Related

Create complex class with factory and builder

background:
I build a class diagram for shopping on the net.
For creating a user interface with tow type (golden-User and silver-User) I use the factory pattern.
But the User class become to be very complex.
How can I create this class by bulider and on the other hand the ability to specify the user type such as the factory will remain on the class name
(will help me to recognize which type is by polymorphism and not by if&else)
The Decorator pattern is a simple solution:
public class Main {
public static void main(String[] args) {
User silverUser = new UserDecorator(new SilverUser("Kyriakos", "Georgiopoulos"));
User goldenUser = new UserDecorator(new GoldenUser("GoldenUser firstName", "GoldenUser lastName"));
User nullUser = new UserDecorator(null);
System.out.println(silverUser.firstName() + " " + silverUser.lastName() + " is " + silverUser.type());
System.out.println(goldenUser.firstName() + " " + goldenUser.lastName() + " is " + goldenUser.type());
System.out.println(nullUser.firstName() + " " + nullUser.lastName() + " is " + nullUser.type());
}
}
interface User {
String firstName();
String lastName();
String type();
}
class SilverUser implements User {
private final String firstName;
private final String lastName;
SilverUser(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String firstName() {
return firstName;
}
public String lastName() {
return lastName;
}
public String type() {
return "SilverUser ";
}
}
class GoldenUser implements User {
private final String firstName;
private final String lastName;
GoldenUser(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String firstName() {
return firstName;
}
public String lastName() {
return lastName;
}
public String type() {
return "GoldenUser ";
}
}
class UserDecorator implements User {
private final User user;
UserDecorator(User user){
this.user = user;
}
public String firstName() {
return user != null && user.firstName() != null && user.firstName().length() > 0 ?
user.firstName() : "";
}
public String lastName() {
return user != null && user.lastName() != null && user.lastName().length() > 0 ?
user.lastName() : "";
}
public String type() {
return user != null ? user.type() : "NullPointerException";
}
}
The intent of the two patterns are different: while Factory creates an object instance (which can hold more other class instances) the Builder's goal is to create object step-by-step and reduce overloaded constructors.
For example (with java snippets):
Factory method
interface for user:
public interface User {
}
GoldUser class:
class GoldUser implements User {
// ... field declarations
// Ctor
GoldUser(fields...){}
// ... methods
}
SilverUser class:
class SilverUser implement User {
// ... field declarations
// Ctor
SilverUser(fields...){}
// ... methods
}
User Factory Class:
public class UserFactory {
// ... user versions
public static int GoldUser = 0;
public static int SilverUser = 1;
// ... private Ctor because we don't want to instantiate this class - only in this example
private UserFactory (){}
// ... creating appropriate User instance
public static User createUser(int userType){
switch (userType){
case GoldUser: return new GoldUser;
case SilverUser: return new SilverUser;
default throw new WrongUserTypeException("Wrong User Type");
}
}
}
in your other class:
// ... code stuff here
User user=UserFactory.createUser(1); // will return new SilverUser instance
// ... other code stuff here
Builder pattern
If you have many fields in your class and only some of them are compulsory, you don't have to create many constructors, a builder will enough:
class UserBuilder{
private static Service_A serviceA; // required
private static Service_B serviceB; // required
private static Service_C serviceC;
private static Service_D serviceD;
private static Service_E serviceE;
// since this builder is singleton
private static UserBuilder builderInstance = new UserBuilder();
private UserBuilder () {};
public static UserBuilder getBuilderInstance (Service_A service_A, Service_B service_B){
serviceA = service_A;
serviceB = service_B;
serviceC = null;
serviceD = null;
serviceE = null;
return builderInstance;
}
public static UserBuilder addServiceC (Service_C service_C) {
serviceC = service_C;
return builderInstance;
}
public static UserBuilder addServiceD (Service_D service_D) {
serviceC = service_D;
return builderInstance;
}
public static UserBuilder addServiceE (Service_E service_E) {
serviceE = service_E;
return builderInstance;
}
public static User build(){
return new User (serviceA, ServiceB, ServiceC, ServiceD, ServiceE);
}
And later you can build a customized User:
UserBuilder aUserBuilder = UserBuilder.getBuilderInstance(aServiceA, aServiceB);
// ... other stuff
aUserBuilder.addServiceE(aServiceE);
///... more stuff
User aUser= aUSerBuilder.addServiceC(aServiceC)
.build(); // will return the fresh built User instance
Hope I could help you!
Regards,
Cs
In this particular case you're not supposed to use Factory to create different instances of the same class. It can be used to create different implementations of one common abstraction. Try implementing IUser interface. Then implement this interface by two classes: GoldenUser and SilverUser. Your Factory will create instance of either GoldenUser or SilverUser and return it as IUser. Also instead of interface IUser you could probably create User abstract class, that will be inherited by GoldenUser and SilverUser.

Mapping DTO with final members in MapStruct

is there a way to map a DTO using MatStruct which have a few final data members as well and cannot have a default constructor , like :
public class TestDto {
private final String testName;
private int id;
private String testCase;
public TestDto(String testName) {
this.testName = testName;
}
public String getTestName() {
return testName;
}
public int getId() {
return id;
}
public String getTestCase() {
return testCase;
}
public void setId(int id) {
this.id = id;
}
public void setTestCase(String testCase) {
this.testCase = testCase;
}
}
please suggest how could this DTO be mapped using MapStruct.
You can use #ObjectFactory that would construct an instance of your DTO.
For example:
#Mapper
public interface MyMapper {
#ObjectFactory
default TestDto create() {
return new TestDto("My Test Name");
}
//the rest of the mappings
}
You can also enhance the #ObjectFactory to accept the source parameter, that you can use to construct the TestDto. You can even use a #Context as an Object Factory.
NB: You don't have to put the #ObjectFactory method in the same Mapper, or even a MapStruct #Mapper. You can put it in any class (or make it static) and then #Mapper(uses = MyFactory.class)

Spring-data-solr config

i met a problem in Studying with Spring data solr,this is my Configuration Class:
#Configuration
#EnableSolrRepositories(basePackages={"cn.likefund.solr.repository"}, multicoreSupport=true)
public class SolrContext {
static final String SOLR_HOST = "http://192.168.11.157:8080/solr";
#Bean
public SolrClient solrClient() {
return new HttpSolrClient(SOLR_HOST);
}
}
and this is my Repository:
package cn.likefund.solr.repository;
import java.util.List;
import org.springframework.data.solr.repository.SolrCrudRepository;
import cn.likefund.solr.model.Activity;
public interface ActivityRepository extends SolrCrudRepository<Activity, String>{
List<Activity> findByName(String name);
}
when I start the application,the message in console is this
error
When I delete the method findByName in the repository,the application start with no problem, i just want to the method findByName worked,anybody know what should i do with this problem?
here is the Activity Class:
#Entity
#SolrDocument(solrCoreName ="core_activity")
public class Activity implements Serializable{
private static final long serialVersionUID = 1566434582540525979L;
#Id
#Field(value = "id")
private String id;
#Field(value = "CREATEDT")
private String createdt;
#Indexed
#Field(value = "NAME")
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getCreatedt() {
return createdt;
}
public void setCreatedt(String createdt) {
this.createdt = createdt;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
So, obviously the CrudRepository is not created .
when you delete the findByName, can you manually query your repo ? (just to be sure the problem comes from the method, and not the SOLR schema)
have you tried to annotate annotate the method to explicitly set the query ? Something like
#Query("NAME:?0")
List findByName(String name);

How to use hibernate lucene search for entity which have many to one relation

I am using Hibernate lucene for searching. Now I want to search with an entity which has a many to one relation
I have two class one is catalogueBase and another one is Subject, here subject has a many-to-one relation (it is one sided relation)
catalogueBase.java class :
#Indexed
#JsonAutoDetect
#Entity
#Table(name="catalogueBase")
public class CatalogueBase extends BaseObject implements Serializable {
// some entities
// ...
private Subject subject;
// setter and get methods
// ...
#Field(index = Index.YES, analyze = Analyze.YES, store = Store.YES)
#ManyToOne
#NotFound(action= NotFoundAction.IGNORE)
#JoinColumn(name = "subject1", insertable = true, updatable=true, nullable = true)
#JsonProperty
public Subject getSubject() {
return subject;
}
public void setSubject(Subject subject) {
this.subject = subject;
}
}
Subject.java (what ever i want to search regarding subject it will be stored in description column) :
#Indexed
#JsonAutoDetect
#Entity
#Table(name="subject")
public class Subject implements java.io.Serializable {
private String description;
// ...
#Column(name = "subjectname", nullable = false, length = 150)
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
// ....
}
this is my DAO method :
private List<CatalogueBase> searchTitle(String queryString) throws InterruptedException {
Session session = getSession();
FullTextSession fullTextSession = Search.getFullTextSession(session);
fullTextSession.createIndexer().startAndWait();
org.hibernate.Query fullTextQuery = null;
List<CatalogueBase> resultList = null;
try{
QueryBuilder queryBuilder = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(CatalogueBase.class).get();
org.apache.lucene.search.Query luceneQuery = queryBuilder.keyword().onFields("title","subject").matching(queryString).createQuery();
fullTextQuery = fullTextSession.createFullTextQuery(luceneQuery, CatalogueBase.class);
List<CatalogueBase> contactList = fullTextQuery.list();
resultList = new ArrayList<CatalogueBase>();;
for (CatalogueBase catalogueBase : contactList) {
catalogueBase.setNoOfCopiesBooks(getCopydetailsCount(catalogueBase.getId()));
catalogueBase.setIssuedCount(getIssuedCount(catalogueBase.getId()));
resultList.add(catalogueBase);
}
} catch(Exception e) {
e.printStackTrace();
}
return resultList;
}
But it's giving an error like: SearchException: Unable to find field subject in com.easylib.elibrary.model.CatalogueBase
And I did something like this post, but error was the same.
I got solution.
I will just post code...
#Indexed // must
#JsonAutoDetect
#Entity
#Table(name="subject")
public class Subject implements java.io.Serializable {
private String description;
#ContainedIn // must
#Field(index = Index.YES, analyze = Analyze.YES, store = Store.YES)
#Column(name = "subjectname", nullable = false, length = 150)
public String getDescription() {
return this.description;
}
}
In catalogue:
#ManyToOne
#NotFound(action= NotFoundAction.IGNORE)
#JoinColumn(name = "subject1", insertable = true, updatable=true, nullable = true)
#JsonProperty
#IndexedEmbedded // must
public Subject getSubject() {
return subject;
}
public void setSubject(Subject subject) {
this.subject = subject;
}
And in the DAO, it must be:
org.apache.lucene.search.Query luceneQuery = queryBuilder.keyword().onFields("subject.description").matching(queryString).createQuery();

Jackson configuration to write enum as object

When I try to serialize and deserialize a Set<ClassA<?>> of generic objects that look as follows:
public class ClassA<T> {
private ClassB datum;
private T value;
...
}
If that T happens to be an enum, it gets written as a String value. This is fine for serialization, but when I deserialize, it's not possible to know if the String value is an enum or not. Jackson then turns the resulting object into a String and you get a ClassA<String> instead of ClassA<SomeEnumType>.
Is there a configuration in Jackson to have it create some hints that the value is an enum? Or perhaps turn the enum into a JSON object rather then a string value?
Is there a configuration in Jackson to have it create some hints that the value is an enum?
It's possible to deserialize to an enum instance from a matching JSON string value. Or is this somehow not applicable to your situation?
Here is an example.
import java.util.Set;
import java.util.TreeSet;
import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
import org.codehaus.jackson.annotate.JsonMethod;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.type.TypeFactory;
public class JacksonFoo
{
public static void main(String[] args) throws Exception
{
ObjectMapper mapper = new ObjectMapper().setVisibility(JsonMethod.FIELD, Visibility.ANY);
String myEnumJson = mapper.writeValueAsString(MyEnum.MyEnum1);
System.out.println(myEnumJson);
MyEnum myEnum = mapper.readValue(myEnumJson, MyEnum.class);
System.out.println(myEnum);
Set<ClassA<MyEnum>> set = new TreeSet<ClassA<MyEnum>>();
set.add(new ClassA<MyEnum>(new ClassB("bValue7"), MyEnum.MyEnum1));
set.add(new ClassA<MyEnum>(new ClassB("bValue8"), MyEnum.MyEnum2));
String setJson = mapper.writeValueAsString(set);
System.out.println(setJson);
TypeFactory typeFactory = TypeFactory.defaultInstance();
Set<ClassA<MyEnum>> setCopy = mapper.readValue(setJson,
typeFactory.constructCollectionType(Set.class,
typeFactory.constructParametricType(ClassA.class, MyEnum.class)));
System.out.println(setCopy);
}
}
class ClassA<T> implements Comparable<ClassA<T>>
{
ClassB datum;
T value;
ClassA()
{
}
ClassA(ClassB datum, T value)
{
this.datum = datum;
this.value = value;
}
#Override
public int compareTo(ClassA<T> o)
{
return 42;
}
#Override
public String toString()
{
return String.format("ClassA: datum=%s, value=%s", datum, value);
}
}
class ClassB
{
String bValue;
ClassB()
{
}
ClassB(String bValue)
{
this.bValue = bValue;
}
#Override
public String toString()
{
return String.format("ClassB: bValue=%s", bValue);
}
}
enum MyEnum
{
MyEnum1("myEnum1", 1), MyEnum2("myEnum2", 2);
String name;
int id;
MyEnum(String name, int id)
{
this.name = name;
this.id = id;
}
}
Output:
"MyEnum1"
MyEnum1
[{"datum":{"bValue":"bValue7"},"value":"MyEnum1"},{"datum":{"bValue":"bValue8"},"value":"MyEnum2"}]
[ClassA: datum=ClassB: bValue=bValue7, value=MyEnum1, ClassA: datum=ClassB: bValue=bValue8, value=MyEnum2]
If for some reason it's necessary to have enums serialized as POJOs, then it appears custom serialization processing is required. Serializing enums with Jackson