App Engine - Query using a class member as parameter - google-app-engine

I have a simple class, relevant details below:
#PersistenceCapable(identityType = IdentityType.APPLICATION)
public class SimpleCategory implements Serializable{
...
public static enum type{
Course,
Category,
Cuisine
}
#Persistent
public type t;
...
}
I am attempting to query all SimpleCategory objects of the same type.
public SimpleCategory[] getCategories(SimpleCategory.type type) {
PersistenceManager pm = PMF.get().getPersistenceManager();
try{
Query q = pm.newQuery(SimpleCategory.class);
q.setFilter("t == categoryType");
q.declareParameters("SimpleCategory.type categoryType");
List<SimpleCategory> cats = (List<SimpleCategory>) q.execute(type);
...
}
This results in a ClassNotResolvedException for SimpleCategory.type. The google hits I've found so far recommended to:
Use query.declareImports to specify the class i.e. q.declareImports("com.test.zach.SimpleCategory.type");
Specify the fully qualified name of SimpleCategory in declareParameters
Neither of these suggestions has worked. By removing .type and recompiling, I can verify that declareParameters can see SimpleCategory just fine, it simply cannot see the SimpleCategory.type, despite the fact that the remainder of the method has full visibility to it.
What am I missing?

You elided (...) whether public static enum type itself is declared #PersistenceCapable. If it isn't, that might explain why the query parser isn't able to resolve a reference to the type class.

Something that has seemed to work for me is writing the query string using an implicit parameter and not using the declareParameters() method.
q.setFilter("t == :categoryType");
List<SimpleCategory> cats = (List<SimpleCategory>) q.execute(type)

Related

how to get range class of objectProperty by its domain class in owlapi?

In my project, I'd like to get all the range class related to the given class by an restricted(somevaluefrom or allvalues from) objectproperties. I can get the restricted subclassofAxioms expressions including the given class, but how can I get the range class in these expressions? In other word, how can I get all the related classes to the given class excluding inherited subclass.
For example:
public static void printSubClassOfAxioms(OWLOntology ontology,OWLReasoner reasoner,OWLClass owlClass){
for(OWLSubClassOfAxiom ax:ontology.getSubClassAxiomsForSubClass(owlClass)){
OWLClassExpression expression=ax.getSuperClass();
System.out.println(ax);
System.out.println(expression);
}
}
The results are:
SubClassOf(<#FourCheesesTopping> <#CheeseTopping>)
SubClassOf(<#FourCheesesTopping> ObjectSomeValuesFrom(<#hasSpiciness> <#Mild>))
SubClassOf(<#FourCheesesTopping> ObjectAllValuesFrom(<#hasCountryOfOrigin> #Country>))
How can I just get the range classes #Country and #Mild
Thank you for your attention!
Write an OWLObjectVisitor and override the visit(OWL... Type) for the restrictions you're interested in. At that point,
type.getFiller()
will yield the class you're after.
Examples are in the documentation: https://github.com/owlcs/owlapi/wiki/Documentation
public class RestrictionVisitor extends OWLClassExpressionVisitor {
#Override
public void visit(#Nonnull OWLObjectSomeValuesFrom ce) {
// This method gets called when a class expression is an existential
// (someValuesFrom) restriction and it asks us to visit it
}
}

Create my own API

I use in my force.com application Apex Classes, and many of them have the same structure, I want to make an API to reuse it after.
For exaple, these are two classes :
//first class
public class insererActAct{
public List<Activites_actuelles__c> accts {get; set;}
public insererActAct(ApexPages.StandardController controller){
accts = new List<Activites_actuelles__c>();
accts.add(new Activites_actuelles__c());
}
public void addrow(){
accts.add(new Activites_actuelles__c());
}
public PageReference deleteRow(){
if (accts.size()>1)
{
accts.remove(accts.size()-1);
}
return null;
}
public PageReference save()
{
insert accts;
Assure__c theParent = new Assure__c(id=accts[0].Activites_actuelles__c);
PageReference acctPage = new ApexPages.StandardController(theParent).view();
acctPage.setRedirect(true);
return acctPage;
}
}
//second class
public class insererEnfants{
public List<Enfants__c> accts {get; set;}
public insererEnfants(ApexPages.StandardController controller){
accts = new List<Enfants__c>();
accts.add(new Enfants__c());
}
public void addrow(){
accts.add(new Enfants__c());
}
public PageReference deleteRow(){
if (accts.size()>1)
{
accts.remove(accts.size()-1);
}
return null;
}
public PageReference save()
{
insert accts;
Assure__c theParent = new Assure__c(id=accts[0].Parent__c);
PageReference acctPage = new ApexPages.StandardController(theParent).view();
acctPage.setRedirect(true);
return acctPage;
}
}
Can any one tell me it is possible or not, if yes, how can I do this, please ?
Do you mean you want to write code that works for different kinds of objects, rather than stating the type of object in the code?
It is possible to do this, by declaring your sObject variables with the sObject type, e.g, instead of
public List<Activites_actuelles__c> accts {get; set;}
you would put
public List<sObject> sObjects{get; set;}
and by referencing fields using get and put, e.g. instead of
Account theAccount = new Account();
theAccount.name = 'Fred';
you would put
sObject theSObject = new SObject();
theSObject.put('name', 'Fred');
I've not tried using code like this in a controller extension, but in theory since you can pass in any standard controller you ought to be OK.
You will need to think about how to create the parent object inside the save method, because you will need to pass in what type you want to create. It's quite complicated but it is possible to take in a string representing the object type (e.g. 'Account') and create a new object of that type:
Schema.getGlobalDescribe().get('Account').newSObject()
will get you a new Account. So you could replace 'Account' with any type passed in as a parameter.
For more information look up Dynamic Apex, Dynamic SOQL and Dynamic DML in the documentation.
A word of warning: Passing around object types and field names as strings means that the compiler will not know those types are mentioned in the code. So if you try and delete a custom object or rename a field, salesforce will not warn you that the object or field is in use and will allow you to do the deletion.
Another word of warning: Although this allows code reuse and that is a benefit, you may find it is not worth it. I avoid writing dynamic apex unless I absolutely have to. It is far more complex than ordinary apex and it is therefore difficult to debug and maitain, especially if someone other than yourself has to maintain it.

java.lang.IllegalStateException : Attempting Create Multiple Associations On Variables of Class

first post here, hoping someone could perhaps shed some light on an issue I've been trying to juggle...
As a part of a school project we're attempting to build a interface to display points on a map and paths on a map.
For our first sprint I managed to work out storing/retrieving items using Objectify - it went great!
Now we're trying to extend the functionality for our next spring. Having problems now trying to store an object of type MapPath (note MapPath and MapData, our two data types, both extend class Data). Brief code snippets as follows :
#Entity
public class Data extends JavaScriptObject
{
#Id
Long id;
private String name;
private String dataSet;
...getters and setters
}
#Subclass
public class MapData extends Data implements Serializable{
{
private String name;
private String address;
private String dataSet;
#Embedded
private Coordinate location;
....constructors, getters/setters
}
#Subclass
public class PathData extends Data implements Serializable{
private String name;
private String address;
private String dataSet;
#Embedded
private Coordinate[] path;
...etc
}
Now hopefully I haven't lost you yet. I have a DataService class that basically handles all transactions. I have the following unit test :
#Test
public void storeOnePath(){
PathData pd = new PathData();
pd.setName("hi");
DataService.storeSingleton(pd);
Data d = DataService.getSingleton("hi");
assertEquals(pd,d);
}
The implementation of getSingleton is as follows :
public static void storeSingleton(Data d){
Objectify obj = ObjectifyService.begin();
obj.put(d);
}
JUnit complains:
java.lang.ExceptionInInitializerError
at com.teamrawket.tests.DataTest.storeOnePath(DataTest.java:59)
...<taken out>
Caused by: java.lang.IllegalStateException: Attempting to create multiple associations on class com.teamrawket.server.MapData for name
at com.googlecode.objectify.impl.Transmog$Visitor.addRootSetter(Transmog.java:298)
at com.googlecode.objectify.impl.Transmog$Visitor.visitField(Transmog.java:231)
at com.googlecode.objectify.impl.Transmog$Visitor.visitClass(Transmog.java:134)
at com.googlecode.objectify.impl.Transmog.<init>(Transmog.java:319)
at com.googlecode.objectify.impl.ConcreteEntityMetadata.<init>(ConcreteEntityMetadata.java:75)
at com.googlecode.objectify.impl.Registrar.registerPolymorphicHierarchy(Registrar.java:128)
at com.googlecode.objectify.impl.Registrar.register(Registrar.java:62)
at com.googlecode.objectify.ObjectifyFactory.register(ObjectifyFactory.java:209)
at com.googlecode.objectify.ObjectifyService.register(ObjectifyService.java:38)
at com.teamrawket.server.DataService.<clinit>(DataService.java:20)
... 27 more
What exactly does "attempting to create multiple associations on class ... for name" imply?
Sorry for the long post and any formatting issues that may arise.
You have repeated field names in your subclasses. You should not declare 'name' and 'dataSet' in both superclasses and subclasses; remove these fields from MapData and PathData and you should be fine.
com.teamrawket.server.MapData refers to the fullPath name for your MapData file. The name at the end refers to the field String name in your MapData class. This whole exception tries to tell you that it already contains a reference for that specific fullPath.
I would say there is another object with the same fullPath already registered. It would be helpful to know where line 59 is exactly as that is where the error occured.

How to know what class is being deserialized in JackSon Deserializer?

I'm using app engine datastore so I have entity like this.
#PersistenceCapable
public class Author {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
#JsonProperty("id")
#JsonSerialize(using = JsonKeySerializer.class)
#JsonDeserialize(using = JsonKeyDeserializer.class)
private Key key;
....
}
When the model is sent to view, it will serialize the Key object as an Id value. Then, if I send data back from view I want to deserialize the Id back to Key object by using JsonKeyDeserializer class.
public class JsonKeyDeserializer extends JsonDeserializer<Key> {
#Override
public Key deserialize(JsonParser jsonParser, DeserializationContext deserializeContext)
throws IOException, JsonProcessingException {
String id = jsonParser.getText();
if (id.isEmpty()) {
return null;
}
// Here is the problem because I have several entities and I can't fix the Author class in this deserializer like this.
// I want to know what class is being deserialized at runtime.
// return KeyFactory.createKey(Author.class.getSimpleName(), Integer.parseInt(id))
}
}
I tried to debug the value in deserialize's parameters but I can't find the way to get the target deserialized class. How can I solve this?
You may have misunderstood the role of KeySerializer/KeyDeserializer: they are used for Java Map keys, and not as generic identifiers in database sense of term "key".
So you probably would need to use regular JsonSerializer/JsonDeserializer instead.
As to type: it is assumed that handlers are constructed for specific types, and no extra type information is passed during serialization or deserialization process: expected type (if handlers are used for different types) must be passed during construction.
When registering general serializers or deserializers, you can do this when implementing Module, as one of the arguments is type for which (de)serializer is requested.
When defining handlers directly for properties (like when using annotations), this information is available on createContextual() callback of interface ContextualSerializer (and -Deserializer), if your handler implements it: BeanProperty is passed to specify property (in this case field with annotation), and you can access its type. This information needs to be stored to be used during (de)serialization.
EDIT: as author pointed out, I actually misread the question: KeySerializer is the class name, not annotation.

Parameter must be an entity type exposed by the DomainService?

Trying to implement a domain service in a SL app and getting the following error:
Parameter 'spFolderCreate' of domain method 'CreateSharePointFolder' must be an entity type exposed by the DomainService.
[EnableClientAccess()]
public class FileUploadService : DomainService
{
public void CreateSharePointFolder(SharePointFolderCreate spFolderCreate)
{
SharePointFolder spf = new SharePointFolder();
spf.CreateFolder_ClientOM(spFolderCreate.listName, spFolderCreate.fileName);
}
[OperationContract]
void CreateSharePointFolder(SharePointFolderCreate spFolderCreate);
[DataContract]
public class SharePointFolderCreate
{
private string m_listName;
private string m_fileName;
[DataMember]
public string listName
{
get { return m_listName; }
set { m_listName = value; }
}
[DataMember]
public string fileName
{
get { return m_fileName; }
set { m_fileName = value; }
}
}
So am I missing something simple here to make this all work?
It may be that the framework is inferring the intended operation because you have the word "Create" prefixing the function name (CreateSharePointFolder). Details of this behaviour can be found here
Although that is all fine for DomainServices and EntityFramework, following the information in that article, it can be inferred that methods beginning "Delete" will be performing a delete of an entity, so must accept an entity as a parameter. The same is true for "Create" or "Insert" prefixed methods. Only "Get" or "Select" methods can take non-entity parameters, making it possible to pass a numeric id (for example) to a "Get" method.
Try changing your method name temporarily to "BlahSharePointFolder" to see if it is this convention of inferrance that's causing your problem.
Also, as there is no metadata defined for your SharePointFolderCreate DC, you might need to decorate the class (in addition to the [DataContract] attribute) with the [MetadataType] attribute. You will see how to implement this if you used the DomainServiceClass wizard and point to an EF model. There is a checkbox at the bottom for generating metadata. Somewhere in your solution.Web project you should find a domainservice.metadata.cs file. In this file, you will find examples of how to use the [MetadataType] attribute.
For the RIA WCF service to work correctly with your own methods, you need to ensure that all entities existing on the parameter list have at least one member with a [Key] attribute defined in their metadata class, and that the entity is returned somewhere on your DomainService in a "Get" method.
HTH
Lee

Resources