diff --git a/OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ETMSample.cs b/OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ETMSample.cs index 2ed77f2e..62d35bfb 100644 --- a/OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ETMSample.cs +++ b/OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ETMSample.cs @@ -159,7 +159,7 @@ async Task RunAsync(string webContextUrl, string user, string passwd, string pro //Get the Creation Factory URL for test cases so that we can create a test case String testcaseCreation = await client.LookupCreationFactoryAsync( serviceProviderUrl, OSLCConstants.OSLC_QM_V2, - testcase.GetRdfTypes()[0].ToString()).ConfigureAwait(false); + testcase.Types.First().ToString()).ConfigureAwait(false); //Create the test case HttpResponseMessage creationResponse = await client.CreateResourceRawAsync( diff --git a/OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/EWMSample.cs b/OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/EWMSample.cs index ba731c93..3a6790b2 100644 --- a/OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/EWMSample.cs +++ b/OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/EWMSample.cs @@ -195,7 +195,7 @@ public async Task RunScenarioAsync(string webContextUrl, string user, string pas //Get the Creation Factory URL for change requests so that we can create one String changeRequestCreation = await client.LookupCreationFactoryAsync( serviceProviderUrl, OSLCConstants.OSLC_CM_V2, - changeRequest.GetRdfTypes()[0].ToString()).ConfigureAwait(false); + changeRequest.Types.First().ToString()).ConfigureAwait(false); //Create the change request HttpResponseMessage creationResponse = await client.CreateResourceRawAsync( @@ -271,7 +271,7 @@ protected override void PrintResourceInfo(ChangeRequest cr) string creationFactoryUrl = await client.LookupCreationFactoryAsync( serviceProviderUrl, OSLCConstants.OSLC_CM_V2, - changeRequest.GetRdfTypes()[0].ToString()).ConfigureAwait(false); + changeRequest.Types.First().ToString()).ConfigureAwait(false); if (string.IsNullOrEmpty(creationFactoryUrl)) { diff --git a/OSLC4Net_SDK/OSLC4Net.ChangeManagement/ChangeRequest.cs b/OSLC4Net_SDK/OSLC4Net.ChangeManagement/ChangeRequest.cs index 6c200c6a..0354aa46 100644 --- a/OSLC4Net_SDK/OSLC4Net.ChangeManagement/ChangeRequest.cs +++ b/OSLC4Net_SDK/OSLC4Net.ChangeManagement/ChangeRequest.cs @@ -354,7 +354,7 @@ public Uri GetInstanceShape() [Obsolete] public Uri[] GetRdfTypes() { - return GetTypes().ToArray(); + return Types.ToArray(); } [OslcDescription("This relationship is loosely coupled and has no specific meaning.")] @@ -716,7 +716,7 @@ public void SetModified(DateTime? modified) [Obsolete] public void SetRdfTypes(Uri[] rdfTypes) { - SetTypes(rdfTypes); + Types = rdfTypes; } public void SetRelatedChangeRequests(Link[] relatedChangeRequests) diff --git a/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/ArchitectureLinkType.cs b/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/ArchitectureLinkType.cs index b53cebb3..5c969a46 100644 --- a/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/ArchitectureLinkType.cs +++ b/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/ArchitectureLinkType.cs @@ -147,7 +147,7 @@ public Uri GetInstanceShape() [Obsolete("User GetTypes() or .Types instead")] public Uri[] GetRdfTypes() { - return GetTypes().ToArray(); + return Types.ToArray(); } [OslcDescription("The scope of a resource is a Uri for the resource's OSLC Service Provider.")] @@ -212,7 +212,7 @@ public void SetModified(DateTime? modified) [Obsolete("User SetTypes() or .Types instead")] public void SetRdfTypes(Uri[] rdfTypes) { - SetTypes(rdfTypes); + Types = rdfTypes; } public void SetServiceProvider(Uri serviceProvider) diff --git a/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/ArchitectureResource.cs b/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/ArchitectureResource.cs index 850d2b4a..2623751b 100644 --- a/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/ArchitectureResource.cs +++ b/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/ArchitectureResource.cs @@ -147,7 +147,7 @@ public Uri GetInstanceShape() [Obsolete("User GetTypes() or .Types instead")] public Uri[] GetRdfTypes() { - return GetTypes().ToArray(); + return Types.ToArray(); } [OslcDescription("A short string representation for the type, example 'Defect'.")] @@ -236,7 +236,7 @@ public void SetModified(DateTime? modified) [Obsolete("User SetTypes() or .Types instead")] public void SetRdfTypes(Uri[] rdfTypes) { - SetTypes(rdfTypes); + Types = rdfTypes; } public void SetDctermsTypes(string[] dctermsTypes) diff --git a/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/AutomationPlan.cs b/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/AutomationPlan.cs index 5d346ff4..d6e9094f 100644 --- a/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/AutomationPlan.cs +++ b/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/AutomationPlan.cs @@ -153,7 +153,7 @@ public Uri GetInstanceShape() [Obsolete("User GetTypes() or .Types instead")] public Uri[] GetRdfTypes() { - return GetTypes().ToArray(); + return Types.ToArray(); } [OslcDescription("The scope of a resource is a Uri for the resource's OSLC Service Provider.")] @@ -245,7 +245,7 @@ public void SetModified(DateTime? modified) [Obsolete("User SetTypes() or .Types instead")] public void SetRdfTypes(Uri[] rdfTypes) { - SetTypes(rdfTypes); + Types = rdfTypes; } public void SetServiceProvider(Uri serviceProvider) diff --git a/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/AutomationRequest.cs b/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/AutomationRequest.cs index 903b0e0a..029ebbd6 100644 --- a/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/AutomationRequest.cs +++ b/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/AutomationRequest.cs @@ -163,7 +163,7 @@ public Uri GetInstanceShape() [Obsolete("User GetTypes() or .Types instead")] public Uri[] GetRdfTypes() { - return GetTypes().ToArray(); + return Types.ToArray(); } [OslcDescription("The scope of a resource is a Uri for the resource's OSLC Service Provider.")] @@ -306,7 +306,7 @@ public void SetModified(DateTime? modified) [Obsolete("User SetTypes() or .Types instead")] public void SetRdfTypes(Uri[] rdfTypes) { - SetTypes(rdfTypes); + Types = rdfTypes; } public void SetServiceProvider(Uri serviceProvider) diff --git a/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/AutomationResult.cs b/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/AutomationResult.cs index 2f967150..06109d50 100644 --- a/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/AutomationResult.cs +++ b/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/AutomationResult.cs @@ -173,7 +173,7 @@ public Uri GetInstanceShape() [Obsolete("User GetTypes() or .Types instead")] public Uri[] GetRdfTypes() { - return GetTypes().ToArray(); + return Types.ToArray(); } [OslcDescription("The scope of a resource is a Uri for the resource's OSLC Service Provider.")] @@ -363,7 +363,7 @@ public void setModified(DateTime? modified) [Obsolete("User SetTypes() or .Types instead")] public void SetRdfTypes(Uri[] rdfTypes) { - SetTypes(rdfTypes); + Types = rdfTypes; } public void setServiceProvider(Uri serviceProvider) diff --git a/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/ChangeRequest.cs b/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/ChangeRequest.cs index 73576ae4..2c8d366d 100644 --- a/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/ChangeRequest.cs +++ b/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/ChangeRequest.cs @@ -341,7 +341,7 @@ public Uri GetInstanceShape() [Obsolete("User GetTypes() or .Types instead")] public Uri[] GetRdfTypes() { - return GetTypes().ToArray(); + return Types.ToArray(); } [OslcDescription("This relationship is loosely coupled and has no specific meaning.")] @@ -696,7 +696,7 @@ public void SetModified(DateTime? modified) [Obsolete("User SetTypes() or .Types instead")] public void SetRdfTypes(Uri[] rdfTypes) { - SetTypes(rdfTypes); + Types = rdfTypes; } public void SetRelatedChangeRequests(Link[] relatedChangeRequests) diff --git a/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/ParameterInstance.cs b/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/ParameterInstance.cs index 29c0a208..caeb6fef 100644 --- a/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/ParameterInstance.cs +++ b/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/ParameterInstance.cs @@ -95,7 +95,7 @@ public Uri GetInstanceShape() [Obsolete("User GetTypes() or .Types instead")] public Uri[] GetRdfTypes() { - return GetTypes().ToArray(); + return Types.ToArray(); } [OslcDescription("The scope of a resource is a Uri for the resource's OSLC Service Provider.")] @@ -130,7 +130,7 @@ public void SetInstanceShape(Uri instanceShape) [Obsolete("User SetTypes() or .Types instead")] public void SetRdfTypes(Uri[] rdfTypes) { - SetTypes(rdfTypes); + Types = rdfTypes; } public void SetServiceProvider(Uri serviceProvider) diff --git a/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/QmResource.cs b/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/QmResource.cs index e8f596a1..48904161 100644 --- a/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/QmResource.cs +++ b/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/QmResource.cs @@ -90,7 +90,7 @@ public Uri GetInstanceShape() [Obsolete("User GetTypes() or .Types instead")] public Uri[] GetRdfTypes() { - return GetTypes().ToArray(); + return Types.ToArray(); } [OslcDescription("The scope of a resource is a Uri for the resource's OSLC Service Provider.")] @@ -136,7 +136,7 @@ public void SetModified(DateTime? modified) [Obsolete("User SetTypes() or .Types instead")] public void SetRdfTypes(Uri[] rdfTypes) { - SetTypes(rdfTypes); + Types = rdfTypes; } public void SetServiceProvider(Uri serviceProvider) diff --git a/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/RequirementBase.cs b/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/RequirementBase.cs index 4720aa07..5747b813 100644 --- a/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/RequirementBase.cs +++ b/OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/RequirementBase.cs @@ -390,7 +390,7 @@ public Uri[] GetCreators() [Obsolete("User GetTypes() or .Types instead")] public Uri[] GetRdfTypes() { - return GetTypes().ToArray(); + return Types.ToArray(); } [OslcDescription("The scope of a resource is a Uri for the resource's OSLC Service Provider.")] @@ -611,7 +611,7 @@ public void SetModified(DateTime? modified) [Obsolete("User SetTypes() or .Types instead")] public void SetRdfTypes(Uri[] rdfTypes) { - SetTypes(rdfTypes); + Types = rdfTypes; } public void SetServiceProvider(Uri? serviceProvider) diff --git a/OSLC4Net_SDK/OSLC4Net.Core.DotNetRdfProvider/DotNetRdfHelper.cs b/OSLC4Net_SDK/OSLC4Net.Core.DotNetRdfProvider/DotNetRdfHelper.cs index a140c81f..7cf4e336 100644 --- a/OSLC4Net_SDK/OSLC4Net.Core.DotNetRdfProvider/DotNetRdfHelper.cs +++ b/OSLC4Net_SDK/OSLC4Net.Core.DotNetRdfProvider/DotNetRdfHelper.cs @@ -1322,7 +1322,7 @@ private static void HandleExtendedProperties(Type resourceType, IExtendedResource extendedResource, IDictionary? properties) { - foreach (var type in extendedResource.GetTypes()) + foreach (var type in extendedResource.Types) { var propertyName = type.ToString(); @@ -1433,7 +1433,7 @@ private static void HandleExtendedValue(Type objType, nestedResource = graph.CreateBlankNode(); } - foreach (var type in any.GetTypes()) + foreach (var type in any.Types) { var propertyName = type.ToString(); diff --git a/OSLC4Net_SDK/OSLC4Net.Core/Exceptions/OslcCoreInvalidOccursException.cs b/OSLC4Net_SDK/OSLC4Net.Core/Exceptions/OslcCoreInvalidOccursException.cs index 1e2ef904..192d4ffc 100644 --- a/OSLC4Net_SDK/OSLC4Net.Core/Exceptions/OslcCoreInvalidOccursException.cs +++ b/OSLC4Net_SDK/OSLC4Net.Core/Exceptions/OslcCoreInvalidOccursException.cs @@ -1,29 +1,29 @@ -/******************************************************************************* - * Copyright (c) 2012 IBM Corporation. - * Copyright (c) 2025 Andrii Berezovskyi and OSLC4Net contributors. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v. 1.0 which accompanies this distribution. - * - * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - *******************************************************************************/ - -using System.Reflection; -using OSLC4Net.Core.Attribute; -using OSLC4Net.Core.Model; - -namespace OSLC4Net.Core.Exceptions; - -public class OslcCoreInvalidOccursException( - Type resourceType, - MethodInfo method, - OslcOccurs oslcOccurs) : OslcCoreApplicationException( - $"OSLC1003: Invalid occurs annotation {OccursExtension.ToString(oslcOccurs.value)} for method {method.Name} of class {resourceType.Name}") -{ - public Type ResourceType { get; } = resourceType; - public MethodInfo Method { get; } = method; - public OslcOccurs OslcOccurs { get; } = oslcOccurs; -} +/******************************************************************************* + * Copyright (c) 2012 IBM Corporation. + * Copyright (c) 2025 Andrii Berezovskyi and OSLC4Net contributors. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v. 1.0 which accompanies this distribution. + * + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + *******************************************************************************/ + +using System.Reflection; +using OSLC4Net.Core.Attribute; +using OSLC4Net.Core.Model; + +namespace OSLC4Net.Core.Exceptions; + +public class OslcCoreInvalidOccursException( + Type resourceType, + MemberInfo method, + OslcOccurs oslcOccurs) : OslcCoreApplicationException( + $"OSLC1003: Invalid occurs annotation {OccursExtension.ToString(oslcOccurs.value)} for method {method.Name} of class {resourceType.Name}") +{ + public Type ResourceType { get; } = resourceType; + public MemberInfo Method { get; } = method; + public OslcOccurs OslcOccurs { get; } = oslcOccurs; +} diff --git a/OSLC4Net_SDK/OSLC4Net.Core/Exceptions/OslcCoreInvalidPropertyTypeException.cs b/OSLC4Net_SDK/OSLC4Net.Core/Exceptions/OslcCoreInvalidPropertyTypeException.cs index 10456609..bb60c978 100644 --- a/OSLC4Net_SDK/OSLC4Net.Core/Exceptions/OslcCoreInvalidPropertyTypeException.cs +++ b/OSLC4Net_SDK/OSLC4Net.Core/Exceptions/OslcCoreInvalidPropertyTypeException.cs @@ -20,11 +20,11 @@ namespace OSLC4Net.Core.Exceptions; /// public class OslcCoreInvalidPropertyTypeException( Type resourceType, - MethodInfo method, + MemberInfo method, Type returnType) : OslcCoreApplicationException( $"OSLC1005: Invalid property type {returnType.Name} returned by method {method.Name} of class {resourceType.Name}") { public Type ResourceType { get; } = resourceType; - public MethodInfo Method { get; } = method; + public MemberInfo Method { get; } = method; public Type ReturnType { get; } = returnType; } diff --git a/OSLC4Net_SDK/OSLC4Net.Core/Exceptions/OslcCoreInvalidRepresentationException.cs b/OSLC4Net_SDK/OSLC4Net.Core/Exceptions/OslcCoreInvalidRepresentationException.cs index 80121b8c..18140a6b 100644 --- a/OSLC4Net_SDK/OSLC4Net.Core/Exceptions/OslcCoreInvalidRepresentationException.cs +++ b/OSLC4Net_SDK/OSLC4Net.Core/Exceptions/OslcCoreInvalidRepresentationException.cs @@ -1,28 +1,28 @@ -/******************************************************************************* - * Copyright (c) 2012 IBM Corporation. - * Copyright (c) 2025 Andrii Berezovskyi and OSLC4Net contributors. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v. 1.0 which accompanies this distribution. - * - * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - *******************************************************************************/ - -using System.Reflection; -using OSLC4Net.Core.Model; - -namespace OSLC4Net.Core.Exceptions; - -public class OslcCoreInvalidRepresentationException( - Type resourceType, - MethodInfo method, - Representation representation) : OslcCoreApplicationException( - $"OSLC1006: Invalid representation {RepresentationExtension.ToString(representation)} defined for method {method.Name} of class {resourceType.Name}") -{ - public Type ResourceType { get; } = resourceType; - public MethodInfo Method { get; } = method; - public Representation Representation { get; } = representation; -} +/******************************************************************************* + * Copyright (c) 2012 IBM Corporation. + * Copyright (c) 2025 Andrii Berezovskyi and OSLC4Net contributors. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v. 1.0 which accompanies this distribution. + * + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + *******************************************************************************/ + +using System.Reflection; +using OSLC4Net.Core.Model; + +namespace OSLC4Net.Core.Exceptions; + +public class OslcCoreInvalidRepresentationException( + Type resourceType, + MemberInfo method, + Representation representation) : OslcCoreApplicationException( + $"OSLC1006: Invalid representation {RepresentationExtension.ToString(representation)} defined for method {method.Name} of class {resourceType.Name}") +{ + public Type ResourceType { get; } = resourceType; + public MemberInfo Method { get; } = method; + public Representation Representation { get; } = representation; +} diff --git a/OSLC4Net_SDK/OSLC4Net.Core/Exceptions/OslcCoreInvalidValueTypeException.cs b/OSLC4Net_SDK/OSLC4Net.Core/Exceptions/OslcCoreInvalidValueTypeException.cs index 38ba72b6..e0424b61 100644 --- a/OSLC4Net_SDK/OSLC4Net.Core/Exceptions/OslcCoreInvalidValueTypeException.cs +++ b/OSLC4Net_SDK/OSLC4Net.Core/Exceptions/OslcCoreInvalidValueTypeException.cs @@ -19,11 +19,11 @@ namespace OSLC4Net.Core.Exceptions; public class OslcCoreInvalidValueTypeException( Type resourceType, - MethodInfo method, + MemberInfo method, ValueType valueType) : OslcCoreApplicationException( $"OSLC1007: Invalid value type {ValueTypeExtension.ToString(valueType)} defined for method {method.Name} of class {resourceType.Name}") { public Type ResourceType { get; } = resourceType; - public MethodInfo Method { get; } = method; + public MemberInfo Method { get; } = method; public ValueType ValueType { get; } = valueType; } diff --git a/OSLC4Net_SDK/OSLC4Net.Core/Model/AbstractResource.cs b/OSLC4Net_SDK/OSLC4Net.Core/Model/AbstractResource.cs index 072216d8..51682f06 100644 --- a/OSLC4Net_SDK/OSLC4Net.Core/Model/AbstractResource.cs +++ b/OSLC4Net_SDK/OSLC4Net.Core/Model/AbstractResource.cs @@ -75,10 +75,7 @@ public IDictionary GetExtendedProperties() /// Get the RDF types /// /// - [OslcDescription("The resource type URIs.")] - [OslcName("type")] - [OslcPropertyDefinition(OslcConstants.RDF_NAMESPACE + "type")] - [OslcTitle("Types")] + [Obsolete("Use .Types property instead")] public ICollection GetTypes() { return types; @@ -88,11 +85,23 @@ public ICollection GetTypes() /// Set the RDF types /// /// + [Obsolete("Use .Types property instead")] public void SetTypes(ICollection types) { this.types = types; } + /// + [OslcDescription("The resource type URIs.")] + [OslcName("type")] + [OslcPropertyDefinition(OslcConstants.RDF_NAMESPACE + "type")] + [OslcTitle("Types")] + public ICollection Types + { + get => types; + set => types = new List(value); + } + /// /// Add an additional RDF type /// diff --git a/OSLC4Net_SDK/OSLC4Net.Core/Model/AbstractResourceRecord.cs b/OSLC4Net_SDK/OSLC4Net.Core/Model/AbstractResourceRecord.cs index 1eec83dc..5386dc56 100644 --- a/OSLC4Net_SDK/OSLC4Net.Core/Model/AbstractResourceRecord.cs +++ b/OSLC4Net_SDK/OSLC4Net.Core/Model/AbstractResourceRecord.cs @@ -16,7 +16,18 @@ public abstract record AbstractResourceRecord : IExtendedResource { public Uri About { get; set; } - public List Types { get; private set; } = new(); + /// + [OslcDescription("The resource type URIs.")] + [OslcName("type")] + [OslcPropertyDefinition(OslcConstants.RDF_NAMESPACE + "type")] + [OslcTitle("Types")] + public List Types { get; set; } = new(); + + ICollection IExtendedResource.Types + { + get => Types; + set => Types = new List(value); + } public IDictionary ExtendedProperties { get; private set; } = new Dictionary(); @@ -43,16 +54,14 @@ public void SetAbout(Uri about) } /// - [OslcDescription("The resource type URIs.")] - [OslcName("type")] - [OslcPropertyDefinition(OslcConstants.RDF_NAMESPACE + "type")] - [OslcTitle("Types")] + [Obsolete("Use .Types property instead")] public ICollection GetTypes() { return Types; } /// + [Obsolete("Use .Types property instead")] public void SetTypes(ICollection types) { Types = new List(types); diff --git a/OSLC4Net_SDK/OSLC4Net.Core/Model/IExtendedResource.cs b/OSLC4Net_SDK/OSLC4Net.Core/Model/IExtendedResource.cs index 7cebcf18..87185116 100644 --- a/OSLC4Net_SDK/OSLC4Net.Core/Model/IExtendedResource.cs +++ b/OSLC4Net_SDK/OSLC4Net.Core/Model/IExtendedResource.cs @@ -38,10 +38,7 @@ public interface IExtendedResource : IResource /// OslcResourceShape#describes() annotation /// /// - [OslcDescription("The resource type URIs.")] - [OslcName("type")] - [OslcPropertyDefinition(OslcConstants.RDF_NAMESPACE + "type")] - [OslcTitle("Types")] + [Obsolete("Use .Types property instead")] ICollection GetTypes(); /// @@ -50,8 +47,20 @@ public interface IExtendedResource : IResource /// OslcResourceShape#describes() annotation. /// /// + [Obsolete("Use .Types property instead")] void SetTypes(ICollection types); + /// + /// Gets or sets the RDF types of this resource. These types will be added to the + /// serialization of the resource in addition to the + /// OslcResourceShape#describes() annotation. + /// + [OslcDescription("The resource type URIs.")] + [OslcName("type")] + [OslcPropertyDefinition(OslcConstants.RDF_NAMESPACE + "type")] + [OslcTitle("Types")] + ICollection Types { get; set; } + /// /// Adds an RDF type to this resource. These types will be added to the /// serialization of the resource in addition to the diff --git a/OSLC4Net_SDK/OSLC4Net.Core/Model/Property.cs b/OSLC4Net_SDK/OSLC4Net.Core/Model/Property.cs index f9b19ccd..d349b3f2 100644 --- a/OSLC4Net_SDK/OSLC4Net.Core/Model/Property.cs +++ b/OSLC4Net_SDK/OSLC4Net.Core/Model/Property.cs @@ -61,7 +61,14 @@ public Property(string name, public int CompareTo(Property o) { - return name.CompareTo(o.GetName()); + var nameComparison = string.Compare(name, o.GetName(), StringComparison.Ordinal); + if (nameComparison != 0) + { + return nameComparison; + } + + return Uri.Compare(propertyDefinition, o.propertyDefinition, + UriComponents.AbsoluteUri, UriFormat.UriEscaped, StringComparison.Ordinal); } public void AddAllowedValue(string allowedValue) diff --git a/OSLC4Net_SDK/OSLC4Net.Core/Model/ResourceShapeFactory.cs b/OSLC4Net_SDK/OSLC4Net.Core/Model/ResourceShapeFactory.cs index c0f2ccd4..9361bf86 100644 --- a/OSLC4Net_SDK/OSLC4Net.Core/Model/ResourceShapeFactory.cs +++ b/OSLC4Net_SDK/OSLC4Net.Core/Model/ResourceShapeFactory.cs @@ -53,6 +53,7 @@ static ResourceShapeFactory() // Object types TYPE_TO_VALUE_TYPE[typeof(BigInteger)] = ValueType.Integer; TYPE_TO_VALUE_TYPE[typeof(DateTime)] = ValueType.DateTime; + TYPE_TO_VALUE_TYPE[typeof(DateTimeOffset)] = ValueType.DateTime; TYPE_TO_VALUE_TYPE[typeof(Uri)] = ValueType.Resource; TYPE_TO_VALUE_TYPE[typeof(ICollection)] = ValueType.Resource; TYPE_TO_VALUE_TYPE[typeof(IEnumerable)] = ValueType.Resource; @@ -146,10 +147,31 @@ private static ResourceShape CreateResourceShape(string baseURI, } } + foreach (var prop in resourceType.GetProperties()) + { + var propertyDefinitionAttribute = + InheritedMethodAttributeHelper.GetAttribute(prop); + if (propertyDefinitionAttribute != null) + { + var propertyDefinition = propertyDefinitionAttribute.value; + if (propertyDefinitions.Contains(propertyDefinition)) + { + throw new OslcCoreDuplicatePropertyDefinitionException(resourceType, + propertyDefinitionAttribute); + } + + propertyDefinitions.Add(propertyDefinition); + + var property = CreateProperty(baseURI, resourceType, prop, + propertyDefinitionAttribute, verifiedTypes); + resourceShape.AddProperty(property); + } + } + return resourceShape; } - private static Property CreateProperty(string baseURI, Type resourceType, MethodInfo method, + private static Property CreateProperty(string baseURI, Type resourceType, MemberInfo method, OslcPropertyDefinition propertyDefinitionAttribute, ISet verifiedTypes) { string name; @@ -160,7 +182,12 @@ private static Property CreateProperty(string baseURI, Type resourceType, Method } else { - name = GetDefaultPropertyName(method); + name = method switch + { + MethodInfo methodInfo => GetDefaultPropertyName(methodInfo), + PropertyInfo propertyInfo => GetDefaultPropertyName(propertyInfo), + _ => throw new ArgumentException("Unsupported member type", nameof(method)) + }; } var propertyDefinition = propertyDefinitionAttribute.value; @@ -171,7 +198,13 @@ private static Property CreateProperty(string baseURI, Type resourceType, Method propertyDefinitionAttribute); } - var returnType = method.ReturnType; + var returnType = method switch + { + MethodInfo methodInfo => methodInfo.ReturnType, + PropertyInfo propertyInfo => propertyInfo.PropertyType, + _ => throw new ArgumentException("Unsupported member type", nameof(method)) + }; + Occurs occurs; var occursAttribute = InheritedMethodAttributeHelper.GetAttribute(method); if (occursAttribute != null) @@ -330,6 +363,18 @@ private static Property CreateProperty(string baseURI, Type resourceType, Method return property; } + private static string GetDefaultPropertyName(PropertyInfo property) + { + var name = property.Name; + var lowercasedFirstCharacter = name.Substring(0, 1).ToLower(CultureInfo.InvariantCulture); + if (name.Length == 1) + { + return lowercasedFirstCharacter; + } + + return string.Concat(lowercasedFirstCharacter, name.AsSpan(1)); + } + private static string GetDefaultPropertyName(MethodInfo method) { var methodName = method.Name; @@ -347,7 +392,7 @@ private static string GetDefaultPropertyName(MethodInfo method) return string.Concat(lowercasedFirstCharacter, methodName.AsSpan(startingIndex + 1)); } - private static ValueType GetDefaultValueType(Type resourceType, MethodInfo method, + private static ValueType GetDefaultValueType(Type resourceType, MemberInfo method, Type componentType) { var valueType = TYPE_TO_VALUE_TYPE[componentType]; @@ -381,7 +426,7 @@ private static Occurs GetDefaultOccurs(Type type) return Occurs.ZeroOrOne; } - private static Type GetComponentType(Type resourceType, MethodInfo method, Type type) + private static Type GetComponentType(Type resourceType, MemberInfo method, Type type) { if (type.IsArray) { @@ -400,6 +445,12 @@ private static Type GetComponentType(Type resourceType, MethodInfo method, Type throw new OslcCoreInvalidPropertyTypeException(resourceType, method, type); } + var underlyingType = Nullable.GetUnderlyingType(type); + if (underlyingType != null) + { + return underlyingType; + } + return type; } @@ -423,10 +474,15 @@ private static void ValidateSetMethodExists(Type resourceType, MethodInfo getMet } } - private static void ValidateUserSpecifiedOccurs(Type resourceType, MethodInfo method, + private static void ValidateUserSpecifiedOccurs(Type resourceType, MemberInfo method, OslcOccurs occursAttribute) { - var returnType = method.ReturnType; + var returnType = method switch + { + MethodInfo methodInfo => methodInfo.ReturnType, + PropertyInfo propertyInfo => propertyInfo.PropertyType, + _ => throw new ArgumentException("Unsupported member type", nameof(method)) + }; var occurs = occursAttribute.value; if (returnType.IsArray || @@ -449,7 +505,7 @@ private static void ValidateUserSpecifiedOccurs(Type resourceType, MethodInfo me } } - private static void ValidateUserSpecifiedValueType(Type resourceType, MethodInfo method, + private static void ValidateUserSpecifiedValueType(Type resourceType, MemberInfo method, ValueType userSpecifiedValueType, Type componentType) { var calculatedValueType = TYPE_TO_VALUE_TYPE[componentType]; @@ -488,7 +544,7 @@ private static void ValidateUserSpecifiedValueType(Type resourceType, MethodInfo throw new OslcCoreInvalidValueTypeException(resourceType, method, userSpecifiedValueType); } - private static void ValidateUserSpecifiedRepresentation(Type resourceType, MethodInfo method, + private static void ValidateUserSpecifiedRepresentation(Type resourceType, MemberInfo method, Representation userSpecifiedRepresentation, Type componentType) { // If user-specified representation is reference and component is not Uri diff --git a/OSLC4Net_SDK/Tests/OSLC4Net.Core.DotNetRdfProviderTests/ResourceShapePropertyAnnotationTests.cs b/OSLC4Net_SDK/Tests/OSLC4Net.Core.DotNetRdfProviderTests/ResourceShapePropertyAnnotationTests.cs new file mode 100644 index 00000000..3329158f --- /dev/null +++ b/OSLC4Net_SDK/Tests/OSLC4Net.Core.DotNetRdfProviderTests/ResourceShapePropertyAnnotationTests.cs @@ -0,0 +1,74 @@ +using OSLC4Net.ChangeManagement; +using OSLC4Net.Core.Attribute; +using OSLC4Net.Core.Model; + +namespace OSLC4Net.Core.DotNetRdfProviderTests; + +[OslcResourceShape(title = "Test Shape", describes = new[] { "http://example.com/TestResource" })] +[OslcNamespace("http://example.com/ns#")] +public class TestResourceWithTypesProperty : AbstractResource +{ + [OslcDescription("Test property")] + [OslcName("name")] + [OslcPropertyDefinition("http://example.com/ns#name")] + [OslcTitle("Name")] + public string Name { get; set; } = ""; +} + +public class ResourceShapePropertyAnnotationTests +{ + [Test] + public async Task CreateResourceShape_DiscoversTypesPropertyAnnotation() + { + var shape = ResourceShapeFactory.CreateResourceShape( + "http://example.com", + OslcConstants.PATH_RESOURCE_SHAPES, + "changeRequest", + typeof(ChangeRequest)); + + var properties = shape.GetProperties(); + var typeProperty = properties.FirstOrDefault(p => + p.GetPropertyDefinition().ToString() == OslcConstants.RDF_NAMESPACE + "type"); + + await Assert.That(typeProperty).IsNotNull(); + await Assert.That(typeProperty!.GetName()).IsEqualTo("type"); + await Assert.That(typeProperty.GetTitle()).IsEqualTo("Types"); + } + + [Test] + public async Task CreateResourceShape_NoDuplicateRdfTypeProperty() + { + var shape = ResourceShapeFactory.CreateResourceShape( + "http://example.com", + OslcConstants.PATH_RESOURCE_SHAPES, + "changeRequest", + typeof(ChangeRequest)); + + var properties = shape.GetProperties(); + var typeProperties = properties.Where(p => + p.GetPropertyDefinition().ToString() == OslcConstants.RDF_NAMESPACE + "type").ToList(); + + // Should be exactly one rdf:type property (from the Types property, not from GetTypes) + await Assert.That(typeProperties.Count).IsEqualTo(1); + } + + [Test] + public async Task CreateResourceShape_MinimalResource_DiscoversTypesAndCustomProperty() + { + var shape = ResourceShapeFactory.CreateResourceShape( + "http://example.com", + OslcConstants.PATH_RESOURCE_SHAPES, + "testResource", + typeof(TestResourceWithTypesProperty)); + + var properties = shape.GetProperties(); + + var nameProperty = properties.FirstOrDefault(p => + p.GetPropertyDefinition().ToString() == "http://example.com/ns#name"); + await Assert.That(nameProperty).IsNotNull(); + + var typeProperty = properties.FirstOrDefault(p => + p.GetPropertyDefinition().ToString() == OslcConstants.RDF_NAMESPACE + "type"); + await Assert.That(typeProperty).IsNotNull(); + } +} diff --git a/OSLC4Net_SDK/Tests/OSLC4Net.Core.DotNetRdfProviderTests/TypesPropertyRoundtripTests.cs b/OSLC4Net_SDK/Tests/OSLC4Net.Core.DotNetRdfProviderTests/TypesPropertyRoundtripTests.cs new file mode 100644 index 00000000..e2a4c0ca --- /dev/null +++ b/OSLC4Net_SDK/Tests/OSLC4Net.Core.DotNetRdfProviderTests/TypesPropertyRoundtripTests.cs @@ -0,0 +1,69 @@ +using System.Net.Http.Headers; +using OSLC4Net.ChangeManagement; +using OSLC4Net.Core.DotNetRdfProvider; +using OSLC4Net.Core.Model; + +namespace OSLC4Net.Core.DotNetRdfProviderTests; + +public class TypesPropertyRoundtripTests +{ + [Test] + public async Task Types_RoundtripsViaSerialization() + { + var cr = new ChangeRequest(new Uri("http://example.com/cr/1")); + cr.Types = new List + { + new Uri(Constants.CHANGE_MANAGEMENT_NAMESPACE + "ChangeRequest"), + new Uri(Constants.CHANGE_MANAGEMENT_NAMESPACE + "Defect") + }; + + var formatter = new RdfXmlMediaTypeFormatter(); + var rdfXml = await RdfHelpers.SerializeAsync(formatter, cr, + OslcMediaType.APPLICATION_RDF_XML_TYPE); + + var deserialized = await RdfHelpers.DeserializeAsync(formatter, rdfXml, + OslcMediaType.APPLICATION_RDF_XML_TYPE); + + await Assert.That(deserialized).IsNotNull(); + await Assert.That(deserialized!.Types.Count).IsEqualTo(cr.Types.Count); + + foreach (var type in cr.Types) + { + await Assert.That(deserialized.Types).Contains(type); + } + } + + [Test] + public async Task Types_PropertyAndGetTypesShareBackingField() + { + var cr = new ChangeRequest(new Uri("http://example.com/cr/2")); + var typeUri = new Uri(Constants.CHANGE_MANAGEMENT_NAMESPACE + "ChangeRequest"); + + cr.Types = new List { typeUri }; + +#pragma warning disable CS0618 + var fromMethod = cr.GetTypes(); +#pragma warning restore CS0618 + + await Assert.That(fromMethod).Contains(typeUri); + await Assert.That(fromMethod.Count).IsEqualTo(1); + } + + [Test] + public async Task Types_EmptyCollectionRoundtrips() + { + var cr = new ChangeRequest(new Uri("http://example.com/cr/3")); + // Don't set any types - should roundtrip as empty + + var formatter = new RdfXmlMediaTypeFormatter(); + var rdfXml = await RdfHelpers.SerializeAsync(formatter, cr, + OslcMediaType.APPLICATION_RDF_XML_TYPE); + + var deserialized = await RdfHelpers.DeserializeAsync(formatter, rdfXml, + OslcMediaType.APPLICATION_RDF_XML_TYPE); + + await Assert.That(deserialized).IsNotNull(); + // The ChangeRequest will have its own rdf:type from OslcResourceShape describes, + // but no extra types should appear beyond that + } +} diff --git a/OSLC4Net_SDK/Tests/OSLC4Net.Core.Tests/ResourceShapeFactoryTests.cs b/OSLC4Net_SDK/Tests/OSLC4Net.Core.Tests/ResourceShapeFactoryTests.cs index 0c406de8..69c007a1 100644 --- a/OSLC4Net_SDK/Tests/OSLC4Net.Core.Tests/ResourceShapeFactoryTests.cs +++ b/OSLC4Net_SDK/Tests/OSLC4Net.Core.Tests/ResourceShapeFactoryTests.cs @@ -116,7 +116,7 @@ public async Task CreateResourceShape_WithRequirementType_ShouldHaveTypeProperty } [Test] - public async Task CreateResourceShape_WithRequirementType_ShouldOnlyHaveGetterMethods() + public async Task CreateResourceShape_WithRequirementType_ShouldHaveMethodAndPropertyAnnotations() { // Arrange var resourceType = typeof(Requirement); @@ -131,8 +131,10 @@ public async Task CreateResourceShape_WithRequirementType_ShouldOnlyHaveGetterMe // Assert var properties = resourceShape.GetProperties(); - await Assert.That(properties.Count).IsEqualTo(1); - await Assert.That(properties[0].GetName()).IsEqualTo("type"); + // Requirement has both Get* methods and C# properties with OSLC annotations + // The Types property from AbstractResourceRecord is also discovered + await Assert.That(properties.Length).IsGreaterThan(1); + await Assert.That(properties.Any(p => p.GetName() == "type")).IsTrue(); } [Test] @@ -315,21 +317,22 @@ public async Task CreateResourceShape_WithISetUriProperty_ShouldMapToResourceVal var properties = resourceShape.GetProperties(); var uriSetProperty = properties.FirstOrDefault(p => p.GetName() == "uriSet"); - await Assert.That(uriSetProperty).IsNull(); - //Assert.Equal("uriSet", uriSetProperty.GetName()); + // ISet properties are discovered via property scanning + await Assert.That(uriSetProperty).IsNotNull(); + await Assert.That(uriSetProperty.GetName()).IsEqualTo("uriSet"); - //var actualValueType = uriSetProperty.GetValueType(); - //var actualOccurs = uriSetProperty.GetOccurs(); + var actualValueType = uriSetProperty.GetValueType(); + var actualOccurs = uriSetProperty.GetOccurs(); - //Assert.NotNull(actualValueType); - //Assert.NotNull(actualOccurs); + await Assert.That(actualValueType).IsNotNull(); + await Assert.That(actualOccurs).IsNotNull(); - //var expectedValueTypeUri = new Uri(ValueTypeExtension.ToString(OSLC4Net.Core.Model.ValueType.Resource)); - //var expectedOccursUri = new Uri(OccursExtension.ToString(OSLC4Net.Core.Model.Occurs.ZeroOrMany)); + var expectedValueTypeUri = new Uri(ValueTypeExtension.ToString(OSLC4Net.Core.Model.ValueType.Resource)); + var expectedOccursUri = new Uri(OccursExtension.ToString(OSLC4Net.Core.Model.Occurs.ZeroOrMany)); - //Assert.Equal(expectedValueTypeUri, actualValueType); - //Assert.Equal(expectedOccursUri, actualOccurs); - //Assert.Equal("http://example.com/uriSet", uriSetProperty.GetPropertyDefinition()?.ToString()); + await Assert.That(actualValueType).IsEqualTo(expectedValueTypeUri); + await Assert.That(actualOccurs).IsEqualTo(expectedOccursUri); + await Assert.That(uriSetProperty.GetPropertyDefinition()?.ToString()).IsEqualTo("http://example.com/uriSet"); } }