I am using a #BeanParam like this:
#GET
public Response listAllPaged(#BeanParam PagedRequest pagedRequest) {
// Do stuff...
}
The bean itself:
public class PagedRequest {
#QueryParam("sortOrder")
#DefaultValue("0")
public int sortOrder;
}
Now I would like to change the type of sortOrder to the following enum:
public enum SortOrder {
ASC("asc"),
DESC("desc");
public final String sortOrder;
SortOrder(String sortOrder) {
this.sortOrder = sortOrder;
}
}
But as soon as I do this:
public class PagedRequest {
#QueryParam("sortOrder")
#DefaultValue("asc")
public SortOrder sortOrder;
}
My REST Endpoint cannot match the signature anymore and returns a 404. Why is that? I thought that the presence of a constructor accepting a single String should allow JAX-RS to do the conversion.
What am I doing wrong?
UPDATE
I managed to make it work like this, but it does not really answer my initial question...
public enum SortOrder {
ASC,
DESC;
public static SortOrder fromString(String param) {
String toUpper = param.toUpperCase();
try {
return valueOf(toUpper);
} catch (Exception e) {
return null;
}
}
}
The Enum.valueOf(String) method is used to resolve the value. Since your SorterOrder enums are uppercase you'd be required to send the parameter in uppercase.
If you want to pass the value in lowercase only you could change the enum names to lower case, e.g. SortOrder.asc.
If you don't know or don't want to care about the case the parameter is sent in you could use a ParamConverter.
public class SortOrderParamConverter implements ParamConverter<SortOrder> {
#Override
public SortOrder fromString(final String value) {
if (value != null) {
return SortOrder.valueOf(value.toUpperCase(Locale.ROOT));
}
return SortOrder.ASC;
}
#Override
public String toString(final SortOrder value) {
return value.name();
}
}
If you want a more generic approach you could create a ParamConverter or all enums.
#Provider
public class EnumParamConverterProvider implements ParamConverterProvider {
#Override
public <T> ParamConverter<T> getConverter(final Class<T> rawType, final Type genericType,
final Annotation[] annotations) {
if (!rawType.isEnum()) {
return null;
}
final Enum<?>[] constants = (Enum<?>[]) rawType.getEnumConstants();
return new ParamConverter<T>() {
#Override
#SuppressWarnings("unchecked")
public T fromString(final String value) {
if (value == null || value.isEmpty()) {
return null;
}
for (Enum<?> e : constants) {
if (e.name().equalsIgnoreCase(value)) {
return (T) e;
}
}
// No match, check toString()
for (Enum<?> e : constants) {
if (e.toString().equalsIgnoreCase(value)) {
return (T) e;
}
}
return null;
}
#Override
public String toString(final T value) {
return value != null ? value.toString() : null;
}
};
}
}
Related
I am trying to get list of Tbcompany table using Transformers.aliasToBean with 2 primary key fields.
I am using SQL SERVER and Hibernate 3.2.4.
My table has 2 primary fields.
Tbcompany.class
public class Tbcompany {
private TbcompanyId id;
private String hcompanycode;
public TbcompanyId getId() {
return id;
}
public void setId(TbcompanyId id) {
this.id = id;
}
public String getHcompanycode() {
return hcompanycode;
}
public void setHcompanycode(String hcompanycode) {
this.hcompanycode = hcompanycode;
}
}
And inside TbcompanyId.class :
public class TbcompanyId
implements Serializable
{
private String companycode;
private String companyname;
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof TbcompanyId)) {
return false;
}
TbcompanyId other = ((TbcompanyId) o);
if (this.companycode == null) {
if (other.companycode!= null) {
return false;
}
} else {
if (!this.companycode.equals(other.companycode)) {
return false;
}
}
if (this.companyname == null) {
if (other.companyname!= null) {
return false;
}
} else {
if (!this.companyname.equals(other.companyname)) {
return false;
}
}
return true;
}
public int hashCode() {
int rtn = 17;
rtn = (rtn* 37);
if (this.companycode!= null) {
rtn = (rtn + this.companycode.hashCode());
}
rtn = (rtn* 37);
if (this.companyname!= null) {
rtn = (rtn + this.companyname.hashCode());
}
return rtn;
}
public String getCompanycode() {
return companycode;
}
public void setCompanycode(String companycode) {
this.companycode = companycode;
}
public String getCompanyname() {
return companyname;
}
public void setCompanyname(String companyname) {
this.companyname = companyname;
}
I want to create a form and use Transformers.aliasToBean to populate the form .
This query :
Query q;
q = session.createQuery("SELECT a.id.companycode as companycode,a.id.companyname as companyname,a.hcompanycode as hcompanycode FROM Tbcompany a");
q.setResultTransformer(Transformers.aliasToBean(Tbcompany.class));
list = q.list();
gives me an error of :
org.hibernate.PropertyNotFoundException: Could not find setter for companycode on class com.loansdb.data.Tbcompany
While this query :
Query q;
q = session.createQuery("SELECT a.id.companycode,a.id.companyname,a.hcompanycode as hcompanycode FROM
Tbcompany a");
q.setResultTransformer(Transformers.aliasToBean(Tbcompany.class));
list = q.list();
gives me this error :
org.hibernate.PropertyNotFoundException: Could not find setter for 0 on class com.loansdb.data.Tbcompany
Does anyone know how to do this?
The aliasToBean transformer use the name of the SQL columns returned and try to find a field with the same name on the class target that have a set method created.
So, your query returns a a.id.companycode:
SELECT a.id.companycode as companycode,a.id.companyname as companyname,a.hcompanycode as hcompanycode FROM Tbcompany a
The error said:
org.hibernate.PropertyNotFoundException: Could not find setter for companycode on class com.loansdb.data.Tbcompany
And your Tbcompany class does not have a setter to companycode.
So, to correct your Tbcompany class and looking your query, seems to me that the class it's something like:
public class Tbcompany {
private String companycode;
private String companycode;
private String companyname;
public String setCompanycode(String companycode) {
this.companycode = companycode;
}
// create the constructor, getters and setters
}
i had problem to read all date from db PostgreSQL and jpa/hibernate ejb
my table has array field see below :
#Entity
public class MyTable{
private Long id;
private String name;
private String[] values;
#Type(type = "com.usertype.StringArrayUserType")
public String[] getValues(){
return values;
}
public void setValues(String[] values){
this.values = values;
}
}
and user type class like this :
package com.almasprocess.model.bl.en;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.usertype.UserType;
import java.io.Serializable;
import java.sql.*;
public class StringArrayUserType implements UserType {
protected static final int[] SQL_TYPES = { Types.ARRAY };
#Override
public Object assemble(Serializable cached, Object owner) throws HibernateException {
return this.deepCopy(cached);
}
#Override
public Object deepCopy(Object value) throws HibernateException {
return value;
}
#Override
public Serializable disassemble(Object value) throws HibernateException {
return (String[]) this.deepCopy(value);
}
#Override
public boolean equals(Object x, Object y) throws HibernateException {
if (x == null) {
return y == null;
}
return x.equals(y);
}
#Override
public int hashCode(Object x) throws HibernateException {
return x.hashCode();
}
#Override
public boolean isMutable() {
return true;
}
#Override
public Object nullSafeGet(ResultSet resultSet, String[] names, SessionImplementor session, Object owner)
throws HibernateException, SQLException {
if (resultSet.wasNull()) {
return null;
}
if(resultSet.getArray(names[0]) == null){
return new Integer[0];
}
Array array = resultSet.getArray(names[0]);
String[] javaArray = (String[]) array.getArray();
return javaArray;
}
#Override
public void nullSafeSet(PreparedStatement statement, Object value, int index, SessionImplementor session)
throws HibernateException, SQLException {
Connection connection = statement.getConnection();
if (value == null) {
statement.setNull(index, SQL_TYPES[0]);
} else {
String[] castObject = (String[]) value;
Array array = connection.createArrayOf("varchar", castObject);
statement.setArray(index, array);
}
}
#Override
public Object replace(Object original, Object target, Object owner) throws HibernateException {
return original;
}
#Override
public Class<String[]> returnedClass() {
return String[].class;
}
#Override
public int[] sqlTypes() {
return new int[] { Types.ARRAY };
}
}
and read date like this in ejb class :
public List readMailBank(){
String query = "select mt from mytable mt";
TypedQuery<StringArrayUserType> typedQuery = em.createQuery(query , StringArrayUserType.class);
List<StringArrayUserType> results = typedQuery.getResultList();
return results;
}
or like this sample code :
public List readMailBank(){
Type stringType = (Type) new TypeLocatorImpl(new TypeResolver()).custom(StringArrayUserType.class);
Query query = em.createNativeQuery("select mt from mytable mt");
query.unwrap(SQLQuery.class).addScalar("mb", (org.hibernate.type.Type) stringType);
List<Mailbank>results = query.getResultList();
return results;
}
but i had this error :
Caused by: java.lang.IllegalArgumentException: Type specified for TypedQuery [com.usertype.StringArrayUserType] is incompatible with query return type [class [Ljava.lang.String;]
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.resultClassChecking(AbstractEntityManagerImpl.java:387) [hibernate-entitymanager-4.3.7.Final.jar:4.3.7.Final]
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:344) [hibernate-entitymanager-4.3.7.Final.jar:4.3.7.Final]
at org.jboss.as.jpa.container.AbstractEntityManager.createQuery(AbstractEntityManager.java:131) [wildfly-jpa-8.2.0.Final.jar:8.2.0.Final]
please help me to read all data from db and fills array in to my array field?
thanks
I think the problem with your first example is that you try to create your query for values in Java which is a String[], but your JPQL asks for MyTable values. Which classes are not extending each other, thus you get an exception about the type incompatibility.
Something like
select mt.values from mytable mt
should give you what you want. (If it doesn't work at once, here is some documentation about selecting values instead of entities.)
What is the cleanest way to map a string column to a Uri property using Dapper?
Here's the cleanest I've been able to come up with so far (using the ITypeMap functionality):
Query:
SELECT * FROM TableWithAStringAddressColumn
POCO:
public class MyPoco
{
[ColumnSetter("DapperAddress")]
public Uri Address { get; set; }
private string DapperAddress { set { this.Address = new Uri(value); } }
}
Extensions:
partial class SqlMapper
{
public static void InitializeTypeMaps()
{
SqlMapper.SetTypeMap(
typeof(MyPoco),
new CustomPropertyTypeMap(typeof(MyPoco), SqlMapper.CustomSetterMapper));
// call out every other class that needs this kind of mapping
}
public static Func<Type, string, PropertyInfo> CustomSetterMapper =
(type, columnName) =>
{
PropertyInfo prop = type
.GetProperties()
.FirstOrDefault(p => string.Equals(columnName, p.Name, StringComparison.OrdinalIgnoreCase));
if (prop != null)
{
// find out if we need to use a different setter
ColumnSetterAttribute setterAttribute = prop.GetCustomAttributes(false).OfType<ColumnSetterAttribute>().LastOrDefault();
if (setterAttribute != null)
{
PropertyInfo setterProp = type
.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.FirstOrDefault(p => string.Equals(setterAttribute.Setter, p.Name, StringComparison.OrdinalIgnoreCase));
if (setterProp == null)
{
throw new InvalidOperationException(string.Format("Setter property misconfigured (Property={0}, Setter={1})", prop.Name, setterAttribute.Setter));
}
else
{
prop = setterProp;
}
}
}
return prop;
};
}
Custom Attribute:
public class ColumnSetterAttribute : Attribute
{
public string Setter { get; set; }
public ColumnSetterAttribute(string setter)
{
this.Setter = setter;
}
}
[edit] I'm looking for a solution I can use without needing to call out all columns in all my queries (I'd like to find a solution where I can use SELECT *).
Seems like a lot of work...
Wouldn't this be ok?
public class MyPoco
{
private string _uriMapper;
public Uri SomeUri
{
get { return new Uri(_uriMapper); }
}
public string Mapper { set { _uriMapper = value; } }
}
Edit:
public class UriContainer
{
private string _uriMapper;
public string UriMapper { set { _uriMapper = value; } }
public int Id { get; set; }
public Uri SomeUri { get {return new Uri(_uriMapper);} }
}
public class DbTests
{
[Test]
public void Can_Get_A_Uri()
{
using (var c = new SqlConnection("hello"))
{
c.Open();
var uri = c.Query<UriContainer>("select *, someuri as urimapper from uris where id = 3").Single();
Console.WriteLine(uri.SomeUri);
}
}
}
I've seen this kind of thing described in various examples showing how to create a REST service which takes arrays or a list of objects as part of the URL.
My question is, how to implement this using RESTeasy?
Something like the following would be how i would assume this to work.
#GET
#Path("/stuff/")
#Produces("application/json")
public StuffResponse getStuffByThings(
#QueryParam("things") List<Thing> things);
Create a StringConverter and a use a wrapper object. Here is a quick and dirty example:
public class QueryParamAsListTest {
public static class Thing {
String value;
Thing(String value){ this.value = value; }
}
public static class ManyThings {
List<Thing> things = new ArrayList<Thing>();
ManyThings(String values){
for(String value : values.split(",")){
things.add(new Thing(value));
}
}
}
static class Converter implements StringConverter<ManyThings> {
public ManyThings fromString(String str) {
return new ManyThings(str);
}
public String toString(ManyThings value) {
//TODO: implement
return value.toString();
}
}
#Path("/")
public static class Service {
#GET
#Path("/stuff/")
public int getStuffByThings(
#QueryParam("things") ManyThings things){
return things.things.size();
}
}
#Test
public void test() throws Exception {
Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
dispatcher.getProviderFactory().addStringConverter(new Converter());
dispatcher.getRegistry().addSingletonResource(new Service());
MockHttpRequest request = MockHttpRequest.get("/stuff?things=a,b,c");
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
Assert.assertEquals("3", response.getContentAsString());
}
}
I think you can also use a StringParamUnmarshaller
I had some luck with this, using Collection rather than List. I was unable to make a StringConverter for List work.
#Provider
public class CollectionConverter implements StringConverter<Collection<String>> {
public Collection<String> fromString(String string) {
if (string == null) {
return Collections.emptyList();
}
return Arrays.asList(string.split(","));
}
public String toString(Collection<String> values) {
final StringBuilder sb = new StringBuilder();
boolean first = true;
for (String value : values) {
if (first) {
first = false;
} else {
sb.append(",");
}
sb.append(value);
}
return sb.toString();
}
}
I did the toString from my head. Be sure to write unit tests for it to verify. But of course, everything is easier and clearer when you use Guava. Can use Joiner and Splitter. Really handy.
Just use a wrapper on its own, no need for anything else.
In your endpoint
#Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
#Path("/find")
#GET
MyResponse find(#QueryParam("ids") Wrapper ids);
And you wrapper looks like this :
public class Wrapper implements Serializable {
private List<BigInteger> ids = Collections.emptyList();
public String toString() {
return Joiner.on(",")
.join(ids);
}
public List<BigInteger> get() {
return ids;
}
public Wrapper(String s) {
if (s == null) {
ids = Collections.emptyList();
}
Iterable<String> splitted = Splitter.on(',')
.split(s);
Iterable<BigInteger> ids = Iterables.transform(splitted, Functionz.stringToBigInteger);
this.ids = Lists.newArrayList(ids);
}
public Wrapper(List<BigInteger> ids) {
this.ids = ids;
}
}
Following is part of service layer which is provided by WCF service :
[Serializable]
public class WaitInfo
{
private string roomName;
private string pName;
private string tagNo;
public string RoomName
{ get { return roomName; } set { this.roomName = value; } }
public string PName
{ get { return pName; } set { this.pName = value; } }
public string TagNo
{ get { return tagNo; } set { this.tagNo = value; } }
}
public class Service1 : IService1
{
public List<WaitInfo> GetWaitingList()
{
MyDBDataContext db = new MyDBDataContext();
var query = from w in db.WAIT_INFOs
select new WaitInfo
{
TagNo = w.PATIENT_INFO.TAG_NO,
RoomName= w.ROOM_INFO.ROOM_NAME,
PName= w.PATIENT_INFO.P_NAME
};
List<WaitInfo> result = query.ToList();
return result;
}
And following is codebehind part of UI layer which is provided by Silverlight
public MainPage()
{
InitializeComponent();
Service1Client s = new Service1Client();
s.GetWaitingListCompleted +=
new EventHandler<GetWaitingListByCompletedEventArgs>( s_GetWaitingListCompleted);
s.GetWaitingListAsync();
}
void s_GetWaitingListCompleted(object sender,
RadControlsSilverlightApplication1.ServiceReference2.GetWaitingListByCompletedEventArgs e)
{
GridDataGrid.ItemsSource = e.Result;
}
And following is xaml code in Silverlight page
<Grid x:Name="LayoutRoot">
<data:DataGrid x:Name="GridDataGrid"></data:DataGrid>
</Grid>
It is very simple code, however what I am thinking weird is property name of object at "e.Result" in the code behind page.
In the service layer, although properties' names are surely "RoomName, PName, TagNo", in the silverlight properties' names are "roomName, pName, tagNo" which are private variable name of the WaitingList Object.
Did I something wrong?
Thanks in advance.
Unless you specifically decorate your class with the DataContract attribute (which you should, instead of Serializable) then a default DataContract will be inferred. For normal Serializable types, this means the fields will be serialized as opposed to the properties.
You can markup your class in either of the following two ways. The latter will use the property accessors when serializing/deserializing your object which may be very useful or be a hassle depending on your circumstances.
[DataContract]
public class WaitInfo
{
[DataMember(Name="RoomName")]
private string roomName;
[DataMember(Name="PName")]
private string pName;
[DataMember(Name="TagNo")]
private string tagNo;
public string RoomName
{ get { return roomName; } set { this.roomName = value; } }
public string PName
{ get { return pName; } set { this.pName = value; } }
public string TagNo
{ get { return tagNo; } set { this.tagNo = value; } }
}
The method I prefer:
[DataContract]
public class WaitInfo
{
private string roomName;
private string pName;
private string tagNo;
[DataMember]
public string RoomName
{ get { return roomName; } set { this.roomName = value; } }
[DataMember]
public string PName
{ get { return pName; } set { this.pName = value; } }
[DataMember]
public string TagNo
{ get { return tagNo; } set { this.tagNo = value; } }
}